asana-gate 0.1.0 → 0.1.1

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/dist/agent-DZc-5ImE.mjs +0 -2
  2. package/dist/api-Cd3qXjya.mjs +0 -2
  3. package/dist/check-bGxfSyj4.mjs +0 -2
  4. package/dist/classification-CGLGDjUo.mjs +0 -2
  5. package/dist/cli.mjs +1 -3
  6. package/dist/commands-BG1kdDd7.mjs +0 -2
  7. package/dist/config-Cz5cQQ6V.mjs +0 -2
  8. package/dist/context-CtHiLMEu.mjs +0 -2
  9. package/dist/evaluate-B3QITkuM.mjs +0 -2
  10. package/dist/explain-DCu8srlb.mjs +0 -2
  11. package/dist/identity-BueTsN0P.mjs +0 -2
  12. package/dist/index.cjs +0 -2
  13. package/dist/index.d.cts +1 -2
  14. package/dist/index.d.mts +1 -2
  15. package/dist/index.mjs +0 -2
  16. package/dist/init-BxNrskT1.mjs +0 -2
  17. package/dist/listing-cache-DNPtaekS.mjs +0 -2
  18. package/dist/mcp-DwzrJ0jR.mjs +0 -2
  19. package/dist/objects-Bs6oIPKt.mjs +0 -2
  20. package/dist/policy-BsO51rPw.mjs +0 -2
  21. package/dist/run-Bd7MACE5.mjs +0 -2
  22. package/dist/session-Bm78YM5P.mjs +0 -2
  23. package/dist/token-CpUi1ReO.mjs +0 -2
  24. package/dist/token-command-BBRNF06S.mjs +0 -2
  25. package/dist/tools-CrftiOhp.mjs +0 -2
  26. package/package.json +2 -2
  27. package/skills/asana-gate/SKILL.md +1 -1
  28. package/skills/asana-gate/references/cli.md +1 -1
  29. package/skills/asana-gate/references/mcp.md +1 -1
  30. package/skills/asana-gate/references/policy.md +1 -1
  31. package/skills/asana-gate/references/tools.md +1 -1
  32. package/dist/agent-DZc-5ImE.mjs.map +0 -1
  33. package/dist/api-Cd3qXjya.mjs.map +0 -1
  34. package/dist/check-bGxfSyj4.mjs.map +0 -1
  35. package/dist/classification-CGLGDjUo.mjs.map +0 -1
  36. package/dist/cli.mjs.map +0 -1
  37. package/dist/commands-BG1kdDd7.mjs.map +0 -1
  38. package/dist/config-Cz5cQQ6V.mjs.map +0 -1
  39. package/dist/context-CtHiLMEu.mjs.map +0 -1
  40. package/dist/evaluate-B3QITkuM.mjs.map +0 -1
  41. package/dist/explain-DCu8srlb.mjs.map +0 -1
  42. package/dist/identity-BueTsN0P.mjs.map +0 -1
  43. package/dist/index.cjs.map +0 -1
  44. package/dist/index.d.cts.map +0 -1
  45. package/dist/index.d.mts.map +0 -1
  46. package/dist/index.mjs.map +0 -1
  47. package/dist/init-BxNrskT1.mjs.map +0 -1
  48. package/dist/listing-cache-DNPtaekS.mjs.map +0 -1
  49. package/dist/mcp-DwzrJ0jR.mjs.map +0 -1
  50. package/dist/objects-Bs6oIPKt.mjs.map +0 -1
  51. package/dist/policy-BsO51rPw.mjs.map +0 -1
  52. package/dist/run-Bd7MACE5.mjs.map +0 -1
  53. package/dist/session-Bm78YM5P.mjs.map +0 -1
  54. package/dist/token-CpUi1ReO.mjs.map +0 -1
  55. package/dist/token-command-BBRNF06S.mjs.map +0 -1
  56. package/dist/tools-CrftiOhp.mjs.map +0 -1
@@ -331,5 +331,3 @@ async function auditAgentFiles(projectDir, version) {
331
331
  ];
332
332
  }
333
333
  export { wireAgents as a, policyWarnings as c, refreshSkillCopies as i, agentsNamed as n, auditEnvironment as o, auditAgentFiles as r, auditReferences as s, AGENT_NAMES as t };
334
-
335
- //# sourceMappingURL=agent-DZc-5ImE.mjs.map
@@ -67,5 +67,3 @@ async function runApi(argv) {
67
67
  });
68
68
  }
69
69
  export { runApi };
70
-
71
- //# sourceMappingURL=api-Cd3qXjya.mjs.map
@@ -95,5 +95,3 @@ async function runCheck(argv, version) {
95
95
  return problems === 0 ? 0 : 1;
96
96
  }
97
97
  export { runCheck };
98
-
99
- //# sourceMappingURL=check-bGxfSyj4.mjs.map
@@ -3687,5 +3687,3 @@ function ruleFor(operationId) {
3687
3687
  return CLASSIFICATION[operationId];
3688
3688
  }
3689
3689
  export { isHttpMethod as A, forbidden as C, noRoute as D, limitExceeded as E, notFound as O, constraintViolation as S, inAction as T, compileRequirement as _, optionFieldsOf as a, GATE_HELP as b, hasConstraints as c, augmentOptFields as d, pick as f, compileApplication as g, specificityOf as h, dataOf as i, matchRoute as j, fillPath as k, labelOf as l, compileState as m, ruleFor as n, redactObject as o, requestedFields as p, createPlanContext as r, constraintsFor as s, CLASSIFICATION as t, FactsLoader as u, memberResolver as v, forbiddenField as w, GateError as x, optionResolver as y };
3690
-
3691
- //# sourceMappingURL=classification-CGLGDjUo.mjs.map
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // package.json
3
- var version = "0.1.0";
3
+ var version = "0.1.1";
4
4
  // src/cli/main.ts
5
5
  /**
6
6
  * The commands, each loading its own modules when it runs, so a command does
@@ -104,5 +104,3 @@ async function main(argv, version) {
104
104
  // src/cli.ts
105
105
  process.exitCode = await main(process.argv.slice(2), version);
106
106
  export {};
107
-
108
- //# sourceMappingURL=cli.mjs.map
@@ -175,5 +175,3 @@ function commandHelp(command) {
175
175
  ].join("\n");
176
176
  }
177
177
  export { nounHelp as a, coerce as c, findCommand as i, parseArgsOptions as l, commandHelp as n, nouns as o, commandsOf as r, usageOf as s, COMMANDS as t, readData as u };
178
-
179
- //# sourceMappingURL=commands-BG1kdDd7.mjs.map
@@ -86,5 +86,3 @@ async function runCache(argv) {
86
86
  return 0;
87
87
  }
88
88
  export { runCache, runSettings };
89
-
90
- //# sourceMappingURL=config-Cz5cQQ6V.mjs.map
@@ -1132,5 +1132,3 @@ function describeError(error) {
1132
1132
  return messageOf(error);
1133
1133
  }
1134
1134
  export { envValue as A, statIfPresent as B, LEVELS as C, fileSink as D, createLogger as E, patchedJson as F, isAbsent as G, unwritableFile as H, privateDir as I, isObject as J, messagesOf as K, privateFile as L, exposureOf as M, firstWhere as N, silentLogger as O, isFile as P, messageOf as Q, readIfPresent as R, splitList as S, compareSpecificity as T, ASANA_ERROR_HELP as U, unwritable as V, AsanaApiError as W, parseJsonc as X, parseJson$1 as Y, stringOf as Z, TOKEN_FILE as _, describeError as a, AsanaClient as b, usageRows as c, SETTINGS_SCHEMA_URL as d, DurationSchema as f, PROJECT_DIR as g, POLICY_FILE as h, UsageError as i, errnoOf as j, ensureLine as k, DEFAULTS as l, resolveDateBound as m, GATED_OPTIONS as n, isUsageError as o, durationMs as p, parseErrorEntries as q, TOKEN_OPTIONS as r, loadCliSettings as s, COMMON_OPTIONS as t, policyCandidates as u, parseYaml as v, PolicyError as w, renderQuery as x, validated as y, readdirIfPresent as z };
1135
-
1136
- //# sourceMappingURL=context-CtHiLMEu.mjs.map
@@ -179,5 +179,3 @@ function grantedActions(policy) {
179
179
  return new Set(policy.rules.filter((rule) => rule.effect === "allow").flatMap((rule) => [...rule.actions]));
180
180
  }
181
181
  export { fieldAllowlist as a, isFilterRule as c, workspaceFacts as d, explainResource as i, isVisible as l, WORKSPACE_BRANCH as n, grantedActions as o, allowedActions as r, isAllowed as s, EMPTY as t, whereMatches as u };
182
-
183
- //# sourceMappingURL=evaluate-B3QITkuM.mjs.map
@@ -116,5 +116,3 @@ async function runExplain(argv) {
116
116
  return 0;
117
117
  }
118
118
  export { runExplain };
119
-
120
- //# sourceMappingURL=explain-DCu8srlb.mjs.map
@@ -47,5 +47,3 @@ async function readSecret(prompt) {
47
47
  }
48
48
  }
49
49
  export { identify as n, readSecret as r, describeUser as t };
50
-
51
- //# sourceMappingURL=identity-BueTsN0P.mjs.map
package/dist/index.cjs CHANGED
@@ -14051,5 +14051,3 @@ exports.serveHttp = serveHttp;
14051
14051
  exports.serveOverStdio = serveOverStdio;
14052
14052
  exports.silentLogger = silentLogger;
14053
14053
  exports.workspaceFacts = workspaceFacts;
14054
-
14055
- //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -3966,5 +3966,4 @@ declare function managedDir(env: NodeJS.ProcessEnv): string;
3966
3966
  * or `home`) is not a project's, so the home directory never is one.
3967
3967
  */
3968
3968
  declare function findProjectDir(cwd: string, home?: string): Promise<string | undefined>;
3969
- export { ALL_ACTIONS, ASANA_API_BASE_URL, type Action, AsanaApiError, AsanaClient, type AsanaClientOptions, type AsanaErrorEntry, AsanaNameResolver, type AsanaRequest, type AsanaResponse, type Branch, CLASSIFICATION, type CompiledRule, type CompiledWhere, type CustomFieldDefinition, type Decision, EXPLICIT_ONLY_ACTIONS, type Explanation, FIELD_VERBS, type Facts, FactsLoader, type FactsLoaderOptions, FileListingCache, Gate, GateError, type GateOptions, type GateRequest, type GateResponse, type HttpMethod, type HttpOptions, type ListingCache, type LoadOptions, type Loaded, type LoadedSettings, type LogLevel, type Logger, type Me, type NameResolver, type OperationId, type OperationRule, type OperationSpec, type Policy, PolicyError, type PolicyFile, PolicyFileSchema, type PolicyRule, type PolicyWhere, RESOURCES, RESOURCE_VERBS, type Reference, type ResolverOptions, type Resource, type RouteMatch, RuleSchema, type ScopeKind, type Serving, type Settings, SettingsError, type SettingsFile, SettingsFileSchema, SettingsSchema, type Verb, WhereSchema, allowedActions, compilePolicy, createAsanaGateServer, createLogger, decide, expandActionPattern, expandActionPatterns, explainResource, fieldAllowlist, findProjectDir, homeDir, isAction, isAllowed, isResource, isVisible, loadPolicyFile, loadSettings, managedDir, matchRoute, parsePolicy, referencesOf, serveHttp, serveOverStdio, silentLogger, workspaceFacts };
3970
- //# sourceMappingURL=index.d.cts.map
3969
+ export { ALL_ACTIONS, ASANA_API_BASE_URL, type Action, AsanaApiError, AsanaClient, type AsanaClientOptions, type AsanaErrorEntry, AsanaNameResolver, type AsanaRequest, type AsanaResponse, type Branch, CLASSIFICATION, type CompiledRule, type CompiledWhere, type CustomFieldDefinition, type Decision, EXPLICIT_ONLY_ACTIONS, type Explanation, FIELD_VERBS, type Facts, FactsLoader, type FactsLoaderOptions, FileListingCache, Gate, GateError, type GateOptions, type GateRequest, type GateResponse, type HttpMethod, type HttpOptions, type ListingCache, type LoadOptions, type Loaded, type LoadedSettings, type LogLevel, type Logger, type Me, type NameResolver, type OperationId, type OperationRule, type OperationSpec, type Policy, PolicyError, type PolicyFile, PolicyFileSchema, type PolicyRule, type PolicyWhere, RESOURCES, RESOURCE_VERBS, type Reference, type ResolverOptions, type Resource, type RouteMatch, RuleSchema, type ScopeKind, type Serving, type Settings, SettingsError, type SettingsFile, SettingsFileSchema, SettingsSchema, type Verb, WhereSchema, allowedActions, compilePolicy, createAsanaGateServer, createLogger, decide, expandActionPattern, expandActionPatterns, explainResource, fieldAllowlist, findProjectDir, homeDir, isAction, isAllowed, isResource, isVisible, loadPolicyFile, loadSettings, managedDir, matchRoute, parsePolicy, referencesOf, serveHttp, serveOverStdio, silentLogger, workspaceFacts };
package/dist/index.d.mts CHANGED
@@ -3966,5 +3966,4 @@ declare function managedDir(env: NodeJS.ProcessEnv): string;
3966
3966
  * or `home`) is not a project's, so the home directory never is one.
3967
3967
  */
3968
3968
  declare function findProjectDir(cwd: string, home?: string): Promise<string | undefined>;
3969
- export { ALL_ACTIONS, ASANA_API_BASE_URL, type Action, AsanaApiError, AsanaClient, type AsanaClientOptions, type AsanaErrorEntry, AsanaNameResolver, type AsanaRequest, type AsanaResponse, type Branch, CLASSIFICATION, type CompiledRule, type CompiledWhere, type CustomFieldDefinition, type Decision, EXPLICIT_ONLY_ACTIONS, type Explanation, FIELD_VERBS, type Facts, FactsLoader, type FactsLoaderOptions, FileListingCache, Gate, GateError, type GateOptions, type GateRequest, type GateResponse, type HttpMethod, type HttpOptions, type ListingCache, type LoadOptions, type Loaded, type LoadedSettings, type LogLevel, type Logger, type Me, type NameResolver, type OperationId, type OperationRule, type OperationSpec, type Policy, PolicyError, type PolicyFile, PolicyFileSchema, type PolicyRule, type PolicyWhere, RESOURCES, RESOURCE_VERBS, type Reference, type ResolverOptions, type Resource, type RouteMatch, RuleSchema, type ScopeKind, type Serving, type Settings, SettingsError, type SettingsFile, SettingsFileSchema, SettingsSchema, type Verb, WhereSchema, allowedActions, compilePolicy, createAsanaGateServer, createLogger, decide, expandActionPattern, expandActionPatterns, explainResource, fieldAllowlist, findProjectDir, homeDir, isAction, isAllowed, isResource, isVisible, loadPolicyFile, loadSettings, managedDir, matchRoute, parsePolicy, referencesOf, serveHttp, serveOverStdio, silentLogger, workspaceFacts };
3970
- //# sourceMappingURL=index.d.mts.map
3969
+ export { ALL_ACTIONS, ASANA_API_BASE_URL, type Action, AsanaApiError, AsanaClient, type AsanaClientOptions, type AsanaErrorEntry, AsanaNameResolver, type AsanaRequest, type AsanaResponse, type Branch, CLASSIFICATION, type CompiledRule, type CompiledWhere, type CustomFieldDefinition, type Decision, EXPLICIT_ONLY_ACTIONS, type Explanation, FIELD_VERBS, type Facts, FactsLoader, type FactsLoaderOptions, FileListingCache, Gate, GateError, type GateOptions, type GateRequest, type GateResponse, type HttpMethod, type HttpOptions, type ListingCache, type LoadOptions, type Loaded, type LoadedSettings, type LogLevel, type Logger, type Me, type NameResolver, type OperationId, type OperationRule, type OperationSpec, type Policy, PolicyError, type PolicyFile, PolicyFileSchema, type PolicyRule, type PolicyWhere, RESOURCES, RESOURCE_VERBS, type Reference, type ResolverOptions, type Resource, type RouteMatch, RuleSchema, type ScopeKind, type Serving, type Settings, SettingsError, type SettingsFile, SettingsFileSchema, SettingsSchema, type Verb, WhereSchema, allowedActions, compilePolicy, createAsanaGateServer, createLogger, decide, expandActionPattern, expandActionPatterns, explainResource, fieldAllowlist, findProjectDir, homeDir, isAction, isAllowed, isResource, isVisible, loadPolicyFile, loadSettings, managedDir, matchRoute, parsePolicy, referencesOf, serveHttp, serveOverStdio, silentLogger, workspaceFacts };
package/dist/index.mjs CHANGED
@@ -13982,5 +13982,3 @@ async function loadSettings(options) {
13982
13982
  };
13983
13983
  }
13984
13984
  export { ALL_ACTIONS, ASANA_API_BASE_URL, AsanaApiError, AsanaClient, AsanaNameResolver, CLASSIFICATION, EXPLICIT_ONLY_ACTIONS, FIELD_VERBS, FactsLoader, FileListingCache, Gate, GateError, OPERATIONS, PolicyError, PolicyFileSchema, RESOURCES, RESOURCE_VERBS, RuleSchema, SettingsError, SettingsFileSchema, SettingsSchema, WhereSchema, allowedActions, compilePolicy, createAsanaGateServer, createLogger, decide, expandActionPattern, expandActionPatterns, explainResource, fieldAllowlist, findProjectDir, homeDir, isAction, isAllowed, isResource, isVisible, loadPolicyFile, loadSettings, managedDir, matchRoute, parsePolicy, referencesOf, serveHttp, serveOverStdio, silentLogger, workspaceFacts };
13985
-
13986
- //# sourceMappingURL=index.mjs.map
@@ -210,5 +210,3 @@ async function runInit(argv, version) {
210
210
  return 0;
211
211
  }
212
212
  export { runInit };
213
-
214
- //# sourceMappingURL=init-BxNrskT1.mjs.map
@@ -82,5 +82,3 @@ var FileListingCache = class {
82
82
  }
83
83
  };
84
84
  export { cacheEntries as n, clearCache as r, FileListingCache as t };
85
-
86
- //# sourceMappingURL=listing-cache-DNPtaekS.mjs.map
@@ -480,5 +480,3 @@ async function runMcp(argv, version) {
480
480
  return 0;
481
481
  }
482
482
  export { runMcp };
483
-
484
- //# sourceMappingURL=mcp-DwzrJ0jR.mjs.map
@@ -4110,5 +4110,3 @@ function resourceOfType(resourceType) {
4110
4110
  return resourceType !== void 0 && Object.hasOwn(RESOURCE_TYPE_MAP, resourceType) ? RESOURCE_TYPE_MAP[resourceType] : void 0;
4111
4111
  }
4112
4112
  export { verbOf as C, readActionOf as S, RESOURCE_VERBS as _, resourceOfType as a, isAction as b, POLICY_SCHEMA_URL as c, READ_OPERATIONS as d, objectOperationOf as f, RESOURCES as g, FIELD_VERBS as h, refsOf as i, PolicyFileSchema as l, EXPLICIT_ONLY_ACTIONS as m, gidsOf as n, GidSchema as o, ALL_ACTIONS as p, refOf as r, OPERATOR_KEYS as s, gidOf as t, isGid as u, VERB_TIERS as v, OPERATIONS as w, isResource as x, actionOf as y };
4113
-
4114
- //# sourceMappingURL=objects-Bs6oIPKt.mjs.map
@@ -3331,5 +3331,3 @@ async function openGate(context) {
3331
3331
  });
3332
3332
  }
3333
3333
  export { describePending as i, openGate as n, ConfirmationRequiredError as r, loadPolicy as t };
3334
-
3335
- //# sourceMappingURL=policy-BsO51rPw.mjs.map
@@ -218,5 +218,3 @@ async function runCommand(noun, argv) {
218
218
  return runGated((policy) => command.spec.request(input, policy), values);
219
219
  }
220
220
  export { runGated as n, runCommand as t };
221
-
222
- //# sourceMappingURL=run-Bd7MACE5.mjs.map
@@ -54,5 +54,3 @@ async function createContext(options, extra) {
54
54
  return connect(await loadCliSettings(options, extra));
55
55
  }
56
56
  export { createContext as n, connect as t };
57
-
58
- //# sourceMappingURL=session-Bm78YM5P.mjs.map
@@ -305,5 +305,3 @@ function tokenFileWarning(source) {
305
305
  return source.file === void 0 ? void 0 : exposureOf(source.file, source.mode);
306
306
  }
307
307
  export { AsanaNameResolver as a, named as c, tokenText as i, tokenOf as n, collect as o, tokenPlaces as r, matches as s, tokenFileWarning as t };
308
-
309
- //# sourceMappingURL=token-CpUi1ReO.mjs.map
@@ -91,5 +91,3 @@ async function runToken(argv) {
91
91
  }
92
92
  }
93
93
  export { runToken };
94
-
95
- //# sourceMappingURL=token-command-BBRNF06S.mjs.map
@@ -1089,5 +1089,3 @@ const TOOLS = [
1089
1089
  })
1090
1090
  ];
1091
1091
  export { TOOLS as n, BATCH_NOTE as t };
1092
-
1093
- //# sourceMappingURL=tools-CrftiOhp.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "asana-gate",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Declarative access-control policy in front of the Asana API, served to AI agents over MCP.",
5
5
  "keywords": [
6
6
  "access-control",
@@ -58,7 +58,7 @@
58
58
  "@changesets/cli": "^3.0.3",
59
59
  "@modelcontextprotocol/client": "^2.4.0",
60
60
  "@types/node": "^26.6.6",
61
- "oxfmt": "^0.75.0",
61
+ "oxfmt": "^0.76.0",
62
62
  "oxlint": "^1.89.0",
63
63
  "oxlint-tsgolint": "^7.0.2004",
64
64
  "publint": "^0.3.25",
@@ -6,7 +6,7 @@ description: >-
6
6
  Also applies when the user mentions allowed_actions, an Asana policy, the gate, or an MCP server for Asana without naming asana-gate.
7
7
  license: Apache-2.0
8
8
  metadata:
9
- version: "0.1.0"
9
+ version: "0.1.1"
10
10
  ---
11
11
 
12
12
  # asana-gate
@@ -1,4 +1,4 @@
1
- <!-- Generated by scripts/generate-skill.ts from the asana-gate README (version 0.1.0); edit the README instead. -->
1
+ <!-- Generated by scripts/generate-skill.ts from the asana-gate README (version 0.1.1); edit the README instead. -->
2
2
 
3
3
  ## CLI
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by scripts/generate-skill.ts from the asana-gate README (version 0.1.0); edit the README instead. -->
1
+ <!-- Generated by scripts/generate-skill.ts from the asana-gate README (version 0.1.1); edit the README instead. -->
2
2
 
3
3
  ## MCP server
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by scripts/generate-skill.ts from the asana-gate README (version 0.1.0); edit the README instead. -->
1
+ <!-- Generated by scripts/generate-skill.ts from the asana-gate README (version 0.1.1); edit the README instead. -->
2
2
 
3
3
  ## Policy
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- Generated by scripts/generate-skill.ts from src/mcp/tools.ts (version 0.1.0); do not edit by hand. -->
1
+ <!-- Generated by scripts/generate-skill.ts from src/mcp/tools.ts (version 0.1.1); do not edit by hand. -->
2
2
 
3
3
  # asana-gate tools
4
4
 
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent-DZc-5ImE.mjs","names":[],"sources":["../src/policy/references.ts","../src/cli/audit.ts","../src/cli/agent.ts"],"sourcesContent":["// Copyright 2026 Shinsuke Mori\n// SPDX-License-Identifier: Apache-2.0\n\nimport type { Resource } from \"../catalog/resources.ts\";\nimport type { CompiledWhere, Policy } from \"./types.ts\";\n\n/** One object a policy's scope names by gid (after names were resolved), and where. */\ninterface Reference {\n\treadonly resource: Resource;\n\treadonly gid: string;\n\t/** The rule's index in the policy file. */\n\treadonly rule: number;\n\t/** The `where` member that names it (`project`, `subtree`, …). */\n\treadonly member: string;\n}\n\n/** The `where` members that name objects, the resource each names, and how to read them. */\nconst MEMBERS: readonly {\n\treadonly member: string;\n\treadonly resource: Resource;\n\treadonly of: (where: CompiledWhere) => Iterable<string> | undefined;\n}[] = [\n\t{ member: \"team\", resource: \"team\", of: (where) => where.teams },\n\t{ member: \"portfolio\", resource: \"portfolio\", of: (where) => where.portfolios },\n\t{ member: \"project\", resource: \"project\", of: (where) => where.projects },\n\t{ member: \"section\", resource: \"section\", of: (where) => where.sections },\n\t{ member: \"task\", resource: \"task\", of: (where) => where.tasks },\n\t{ member: \"subtree\", resource: \"task\", of: (where) => where.subtrees },\n\t{ member: \"tag\", resource: \"tag\", of: (where) => where.tags },\n\t{ member: \"assignee\", resource: \"user\", of: (where) => where.assignees },\n\t{ member: \"created_by\", resource: \"user\", of: (where) => where.createdBy },\n\t{\n\t\tmember: \"custom_field\",\n\t\tresource: \"custom_field\",\n\t\tof: (where) => where.customFields?.map((predicate) => predicate.fieldGid),\n\t},\n];\n\n/** Every object the policy's scopes name, once per rule and member (a rule's statements share one scope). */\nfunction referencesOf(policy: Policy): Reference[] {\n\tconst references = new Map<string, Reference>();\n\tfor (const rule of policy.rules) {\n\t\tfor (const { member, resource, of } of MEMBERS) {\n\t\t\tfor (const gid of of(rule.where) ?? []) {\n\t\t\t\treferences.set(`${rule.index}:${member}:${gid}`, {\n\t\t\t\t\tresource,\n\t\t\t\t\tgid,\n\t\t\t\t\trule: rule.index,\n\t\t\t\t\tmember,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\treturn [...references.values()];\n}\n\nexport { referencesOf };\nexport type { Reference };\n","// Copyright 2026 Shinsuke Mori\n// SPDX-License-Identifier: Apache-2.0\n\nimport { EXPLICIT_ONLY_ACTIONS, verbOf } from \"../catalog/resources.ts\";\nimport type { FactsLoader, Loaded } from \"../gate/facts.ts\";\nimport { messageOf } from \"../log.ts\";\nimport { type Branch, grantedActions, isFilterRule } from \"../policy/evaluate.ts\";\nimport { type Reference, referencesOf } from \"../policy/references.ts\";\nimport type { CompiledRule, Policy } from \"../policy/types.ts\";\nimport { exposureOf, statIfPresent, unwritableFile } from \"../system.ts\";\nimport type { CommandContext } from \"./session.ts\";\nimport { tokenFileWarning } from \"./token.ts\";\n\n/** What `check` audits: the policy's claims against Asana, and the environment the gate runs in. */\n\n/** Something `check` found: a problem fails the command, a warning does not. */\ninterface Finding {\n\treadonly level: \"problem\" | \"warning\";\n\treadonly text: string;\n}\n\nconst problem = (text: string): Finding => ({ level: \"problem\", text });\nconst warning = (text: string): Finding => ({ level: \"warning\", text });\n\n/** The rules once each: a file rule compiles to statements that share its index and scope. */\nfunction fileRules(policy: Policy): CompiledRule[] {\n\treturn [...new Map(policy.rules.map((rule) => [rule.index, rule])).values()];\n}\n\n/** Rules that say less than they seem to. */\nfunction policyWarnings(policy: Policy): Finding[] {\n\tconst findings: Finding[] = [];\n\tconst granted = grantedActions(policy);\n\tconst explicit = [...granted].filter((action) => EXPLICIT_ONLY_ACTIONS.has(action));\n\tif (explicit.length > 0) {\n\t\tfindings.push(warning(`explicit-only actions granted: ${explicit.join(\", \")}`));\n\t}\n\tfor (const rule of policy.rules) {\n\t\tif (isFilterRule(rule) && [...rule.actions].some((action) => verbOf(action) === \"read\")) {\n\t\t\tfindings.push(\n\t\t\t\twarning(\n\t\t\t\t\t`rules[${rule.index}] allows read through a tag/assignee/custom_field filter; filters never make objects visible, so that part has no effect`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\tif (granted.size === 0) {\n\t\tfindings.push(warning(\"no rule allows anything; every request will be refused\"));\n\t}\n\tfor (const rule of fileRules(policy)) {\n\t\tfor (const predicate of rule.where.customFields ?? []) {\n\t\t\tfor (const value of predicate.unmatched ?? []) {\n\t\t\t\tfindings.push(\n\t\t\t\t\twarning(\n\t\t\t\t\t\t`rules[${rule.index}].where.custom_field ${predicate.fieldGid}: \"${value}\" is not an option of the field`,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\treturn findings;\n}\n\n/** Whether a section sits in one of the projects of the rule naming it (a rule without projects takes any). */\nfunction inRuleProject(policy: Policy, reference: Reference, branches: readonly Branch[]): boolean {\n\tconst projects = policy.rules.find((rule) => rule.index === reference.rule)?.where.projects;\n\treturn (\n\t\tprojects === undefined ||\n\t\tbranches.some((branch) => branch.project !== undefined && projects.has(branch.project))\n\t);\n}\n\n/** Loads one object a scope names; resolves to why it failed when Asana did not answer it. */\nasync function loadOrFailure(\n\tloader: FactsLoader,\n\treference: Reference,\n): Promise<Loaded | undefined | string> {\n\ttry {\n\t\treturn await loader.load(reference.resource, reference.gid);\n\t} catch (error) {\n\t\treturn messageOf(error);\n\t}\n}\n\n/** Loads every object the scopes name and reports the ones that are gone, elsewhere, or misplaced. */\nasync function auditReferences(\n\tpolicy: Policy,\n\tloader: FactsLoader,\n): Promise<{ checked: number; findings: Finding[] }> {\n\tconst references = referencesOf(policy);\n\tconst objects = await Promise.all(\n\t\treferences.map((reference) => loadOrFailure(loader, reference)),\n\t);\n\tconst findings: Finding[] = [];\n\tfor (const [index, reference] of references.entries()) {\n\t\tconst at = `rules[${reference.rule}].where.${reference.member} ${reference.gid}`;\n\t\tconst loaded = objects[index];\n\t\tif (typeof loaded === \"string\") {\n\t\t\tfindings.push(problem(`${at}: could not be checked (${loaded})`));\n\t\t} else if (loaded === undefined) {\n\t\t\tfindings.push(problem(`${at}: not found (deleted, or not visible to this token)`));\n\t\t} else if (reference.resource !== \"user\" && loaded.facts.workspace !== policy.workspace) {\n\t\t\tfindings.push(\n\t\t\t\tproblem(\n\t\t\t\t\t`${at}: in another workspace (${loaded.facts.workspace}), so the rule never applies`,\n\t\t\t\t),\n\t\t\t);\n\t\t} else if (\n\t\t\treference.resource === \"section\" &&\n\t\t\t!inRuleProject(policy, reference, loaded.facts.branches)\n\t\t) {\n\t\t\tfindings.push(\n\t\t\t\tproblem(`${at}: not a section of the rule's project, so the rule never applies`),\n\t\t\t);\n\t\t}\n\t}\n\treturn { checked: references.length, findings };\n}\n\n/** The directories the gate writes to, as the process found them, and the token and log files' permissions. */\nasync function auditEnvironment(context: CommandContext): Promise<Finding[]> {\n\tconst { settings } = context.loaded;\n\tconst findings: Finding[] = [];\n\tconst cacheProblem = await context.cache?.unwritable();\n\tif (cacheProblem !== undefined) {\n\t\tfindings.push(\n\t\t\twarning(\n\t\t\t\t`cache: ${settings.cache.dir} is not writable (${cacheProblem}); names are read from Asana each run (cache.enabled: false makes that intended)`,\n\t\t\t),\n\t\t);\n\t}\n\t// Opening the log stream fails later than it returns, so the file is probed here too.\n\tconst { file } = context.log;\n\tconst logProblem =\n\t\tcontext.log.problem ?? (typeof file === \"string\" ? await unwritableFile(file) : undefined);\n\tif (logProblem !== undefined) {\n\t\tfindings.push(\n\t\t\twarning(`log: ${file ?? \"\"} cannot be opened (${logProblem}); warnings reach stderr only`),\n\t\t);\n\t}\n\t// Created owner-only, but one that was there already keeps its mode.\n\tconst logInfo = typeof file === \"string\" ? await statIfPresent(file) : undefined;\n\tconst logExposure = typeof file === \"string\" ? exposureOf(file, logInfo?.mode) : undefined;\n\tif (logExposure !== undefined) {\n\t\tfindings.push(warning(`log: ${logExposure}`));\n\t}\n\tconst token = tokenFileWarning(context.token);\n\tif (token !== undefined) {\n\t\tfindings.push(warning(`token: ${token}`));\n\t}\n\treturn findings;\n}\n\nexport { auditEnvironment, auditReferences, policyWarnings, warning };\nexport type { Finding };\n","// Copyright 2026 Shinsuke Mori\n// SPDX-License-Identifier: Apache-2.0\n\nimport { cp, rm } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\n\nimport { isObject, type JsonObject, parseJsonc } from \"../json.ts\";\nimport { messageOf } from \"../log.ts\";\nimport { POLICY_FILE, PROJECT_DIR, TOKEN_FILE } from \"../settings/paths.ts\";\nimport { firstWhere, isFile, patchedJson, readIfPresent } from \"../system.ts\";\nimport { parseYaml } from \"../yaml.ts\";\nimport { type Finding, warning } from \"./audit.ts\";\nimport { UsageError } from \"./context.ts\";\n\n/**\n * How a repository is wired for a coding agent: the gate as a project MCP\n * server in the agent's own config file, a copy of the skill where the agent\n * reads skills, and, where the agent honors one, a rule that keeps the token\n * file from it. The MCP server keeps every copy of the skill current.\n */\n\nconst SKILL = \"asana-gate\";\nconst TOKEN_DENY = `Read(./${PROJECT_DIR}/${TOKEN_FILE})`;\n\n/** What one agent reads. */\ninterface Agent {\n\treadonly name: string;\n\t/** The file its MCP servers are declared in, and the member they sit under. */\n\treadonly mcpFile: string;\n\treadonly serversKey: string;\n\t/** The directories it reads project skills from; `init` writes the first. */\n\treadonly skillsDirs: readonly [string, ...string[]];\n\t/** The file its standing instructions live in. */\n\treadonly instructionsFile: string;\n\t/** The settings file that takes a rule keeping it from the token file, when it honors one. */\n\treadonly tokenGuard?: string;\n}\n\nconst AGENTS: readonly Agent[] = [\n\t{\n\t\tname: \"claude-code\",\n\t\tmcpFile: \".mcp.json\",\n\t\tserversKey: \"mcpServers\",\n\t\tskillsDirs: [join(\".claude\", \"skills\")],\n\t\tinstructionsFile: \"CLAUDE.md\",\n\t\ttokenGuard: join(\".claude\", \"settings.json\"),\n\t},\n\t{\n\t\tname: \"vscode\",\n\t\tmcpFile: join(\".vscode\", \"mcp.json\"),\n\t\tserversKey: \"servers\",\n\t\tskillsDirs: [join(\".agents\", \"skills\"), join(\".github\", \"skills\"), join(\".claude\", \"skills\")],\n\t\tinstructionsFile: join(\".github\", \"copilot-instructions.md\"),\n\t},\n\t{\n\t\tname: \"cursor\",\n\t\tmcpFile: join(\".cursor\", \"mcp.json\"),\n\t\tserversKey: \"mcpServers\",\n\t\tskillsDirs: [join(\".agents\", \"skills\"), join(\".cursor\", \"skills\"), join(\".claude\", \"skills\")],\n\t\tinstructionsFile: \"AGENTS.md\",\n\t},\n];\n\n/** The agents `init --agent` knows. */\nconst AGENT_NAMES = AGENTS.map((agent) => agent.name);\n\n/** Every directory an agent may read the skill from, so that a copy anywhere is kept current. */\nconst SKILL_DIRS = [...new Set(AGENTS.flatMap((agent) => agent.skillsDirs))];\n\nconst usage = (message: string): Error => new UsageError(message);\n\n/** The agents the names stand for; an unknown name is a usage error. */\nfunction agentsNamed(names: readonly string[]): Agent[] {\n\treturn names.map((name) => {\n\t\tconst agent = AGENTS.find((candidate) => candidate.name === name);\n\t\tif (agent === undefined) {\n\t\t\tthrow usage(`unknown agent \"${name}\" (known: ${AGENT_NAMES.join(\", \")})`);\n\t\t}\n\t\treturn agent;\n\t});\n}\n\n/** The skill shipped in the package: `skills/asana-gate` beside `dist` (or beside `src` in a checkout). */\nasync function packagedSkillDir(): Promise<string> {\n\tconst here = import.meta.dirname;\n\tconst roots = [here, join(here, \"..\"), join(here, \"..\", \"..\")];\n\tconst root = await firstWhere(roots, (dir) => isFile(join(dir, \"skills\", SKILL, \"SKILL.md\")));\n\tif (root === undefined) {\n\t\tthrow new Error(\"the packaged skill is missing\");\n\t}\n\treturn join(root, \"skills\", SKILL);\n}\n\n/** A copy of the skill in the project: its directory, and the version its frontmatter carries. */\ninterface SkillCopy {\n\treadonly dir: string;\n\treadonly version: string;\n}\n\n/** The version in a copied SKILL.md's frontmatter, or `undefined` when no readable copy is at `dir`. */\nasync function copiedVersion(dir: string): Promise<string | undefined> {\n\tconst text = await readIfPresent(join(dir, \"SKILL.md\"));\n\tconst frontmatter =\n\t\ttext === undefined ? undefined : /^---\\r?\\n(?<yaml>.*?)\\r?\\n---/su.exec(text)?.groups?.yaml;\n\tif (frontmatter === undefined) {\n\t\treturn undefined;\n\t}\n\ttry {\n\t\tconst parsed = parseYaml(frontmatter, \"SKILL.md\", (message) => new Error(message));\n\t\tconst metadata = isObject(parsed) && isObject(parsed.metadata) ? parsed.metadata : {};\n\t\treturn typeof metadata.version === \"string\" ? metadata.version : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** The copies of the skill in the project, wherever an agent reads them. */\nasync function skillCopies(projectDir: string): Promise<SkillCopy[]> {\n\tconst copies = await Promise.all(\n\t\tSKILL_DIRS.map(async (dir) => ({\n\t\t\tdir: join(dir, SKILL),\n\t\t\tversion: await copiedVersion(join(projectDir, dir, SKILL)),\n\t\t})),\n\t);\n\treturn copies.filter((copy): copy is SkillCopy => copy.version !== undefined);\n}\n\n/** Replaces `target` with a fresh copy of the packaged skill at `source`, its eval cases left out. */\nasync function copySkill(source: string, target: string): Promise<void> {\n\tawait rm(target, { recursive: true, force: true });\n\tawait cp(source, target, { recursive: true, filter: (path) => basename(path) !== \"evals\" });\n}\n\n/** The MCP server entry that starts the gate for this project, pinned to this version. */\nfunction serverEntry(version: string): JsonObject {\n\treturn { type: \"stdio\", command: \"npx\", args: [\"-y\", `${SKILL}@${version}`, \"mcp\"] };\n}\n\n/** The version the gate's entry in an agent's MCP file pins, when the entry is there. */\nfunction pinnedVersion(document: JsonObject, agent: Agent): string | undefined {\n\tconst servers = document[agent.serversKey];\n\tconst entry = isObject(servers) && isObject(servers[SKILL]) ? servers[SKILL] : {};\n\tconst args = Array.isArray(entry.args) ? (entry.args as unknown[]) : [];\n\tconst spec = args.find(\n\t\t(arg): arg is string => typeof arg === \"string\" && arg.startsWith(`${SKILL}@`),\n\t);\n\treturn spec?.slice(SKILL.length + 1);\n}\n\n/** What `init --agent` did, and what the person still has to do. */\ninterface Wiring {\n\treadonly written: string[];\n\t/** Per agent, the standing instructions to add and the file they belong in. */\n\treadonly instructions: { readonly file: string; readonly text: string }[];\n\treadonly notes: string[];\n}\n\n/** What an agent's standing instructions should say so that it reaches Asana only through the gate. */\nfunction instructionsFor(agent: Agent): string {\n\treturn [\n\t\t\"## Asana\",\n\t\t\"\",\n\t\t`Tasks for this repository live in the Asana project \"<project>\", reached only through asana-gate: the \\`asana-gate\\` MCP server in ${agent.mcpFile}, governed by ${PROJECT_DIR}/${POLICY_FILE}.`,\n\t\t`Read ${join(agent.skillsDirs[0], SKILL, \"SKILL.md\")} before touching Asana.`,\n\t\t`Never call the Asana API any other way, and never read ${PROJECT_DIR}/${TOKEN_FILE}.`,\n\t].join(\"\\n\");\n}\n\n/** Wires `projectDir` for `agents`: skill copies, MCP entries and, where honored, the token rule. */\nasync function wireAgents(\n\tprojectDir: string,\n\tagents: readonly Agent[],\n\tversion: string,\n): Promise<Wiring> {\n\tconst source = await packagedSkillDir();\n\tconst skillDirs = [...new Set(agents.map((agent) => agent.skillsDirs[0]))];\n\tconst guards = [\n\t\t...new Set(agents.map((agent) => agent.tokenGuard).filter((file) => file !== undefined)),\n\t];\n\t// Every file is read and patched first, so one that cannot be parsed leaves the project as it was.\n\tconst writes = await Promise.all([\n\t\t...agents.map((agent) =>\n\t\t\tpatchedJson(join(projectDir, agent.mcpFile), usage, (document) => {\n\t\t\t\tconst current = document[agent.serversKey];\n\t\t\t\tconst servers = isObject(current) ? current : {};\n\t\t\t\tservers[SKILL] = serverEntry(version);\n\t\t\t\tdocument[agent.serversKey] = servers;\n\t\t\t}),\n\t\t),\n\t\t...guards.map((file) =>\n\t\t\tpatchedJson(join(projectDir, file), usage, (document) => {\n\t\t\t\tconst permissions = isObject(document.permissions) ? document.permissions : {};\n\t\t\t\tconst deny = Array.isArray(permissions.deny) ? (permissions.deny as unknown[]) : [];\n\t\t\t\tif (!deny.includes(TOKEN_DENY)) {\n\t\t\t\t\tdeny.push(TOKEN_DENY);\n\t\t\t\t}\n\t\t\t\tpermissions.deny = deny;\n\t\t\t\tdocument.permissions = permissions;\n\t\t\t}),\n\t\t),\n\t]);\n\tawait Promise.all([\n\t\t...skillDirs.map((dir) => copySkill(source, join(projectDir, dir, SKILL))),\n\t\t...writes.map((write) => write()),\n\t]);\n\tconst unguarded = agents\n\t\t.filter((agent) => agent.tokenGuard === undefined)\n\t\t.map((agent) => agent.name);\n\treturn {\n\t\twritten: [\n\t\t\t...skillDirs.map((dir) => join(dir, SKILL)),\n\t\t\t...agents.map((agent) => agent.mcpFile),\n\t\t\t...guards,\n\t\t],\n\t\tinstructions: agents.map((agent) => ({\n\t\t\tfile: agent.instructionsFile,\n\t\t\ttext: instructionsFor(agent),\n\t\t})),\n\t\tnotes:\n\t\t\tunguarded.length === 0\n\t\t\t\t? []\n\t\t\t\t: [\n\t\t\t\t\t\t`${unguarded.join(\" and \")} cannot be kept from reading files in the project, so keep the token out of it: \"asana-gate token set --user\" or $ASANA_ACCESS_TOKEN.`,\n\t\t\t\t\t],\n\t};\n}\n\n/** Rewrites every copy of the skill in the project that is from another version; resolves to the directories refreshed. */\nasync function refreshSkillCopies(projectDir: string, version: string): Promise<string[]> {\n\tconst copies = await skillCopies(projectDir);\n\tconst stale = copies.filter((copy) => copy.version !== version);\n\tif (stale.length === 0) {\n\t\treturn [];\n\t}\n\tconst source = await packagedSkillDir();\n\tawait Promise.all(stale.map((copy) => copySkill(source, join(projectDir, copy.dir))));\n\treturn stale.map((copy) => copy.dir);\n}\n\n/** One agent's MCP file as `check` sees it: the version it pins, or why it cannot be read. */\ninterface Pin {\n\treadonly file: string;\n\treadonly version?: string;\n\treadonly problem?: string;\n}\n\nasync function pinOf(projectDir: string, agent: Agent): Promise<Pin> {\n\ttry {\n\t\tconst text = await readIfPresent(join(projectDir, agent.mcpFile));\n\t\tconst document = text === undefined ? undefined : parseJsonc(text, agent.mcpFile, usage);\n\t\tconst version = isObject(document) ? pinnedVersion(document, agent) : undefined;\n\t\treturn { file: agent.mcpFile, ...(version !== undefined && { version }) };\n\t} catch (error) {\n\t\treturn { file: agent.mcpFile, problem: messageOf(error) };\n\t}\n}\n\n/** Agent files that belong to another version of asana-gate than this one. */\nasync function auditAgentFiles(projectDir: string, version: string): Promise<Finding[]> {\n\tconst [copies, pins] = await Promise.all([\n\t\tskillCopies(projectDir),\n\t\tPromise.all(AGENTS.map((agent) => pinOf(projectDir, agent))),\n\t]);\n\treturn [\n\t\t...pins\n\t\t\t.filter((pin) => pin.problem !== undefined)\n\t\t\t.map((pin) => warning(`${pin.problem ?? \"\"}; the agent may not start the gate`)),\n\t\t...copies\n\t\t\t.filter((copy) => copy.version !== version)\n\t\t\t.map((copy) =>\n\t\t\t\twarning(\n\t\t\t\t\t`${copy.dir} is the skill of asana-gate ${copy.version}; this is ${version}: the MCP server refreshes it when it starts, or run \"asana-gate init --agent …\"`,\n\t\t\t\t),\n\t\t\t),\n\t\t...pins\n\t\t\t.filter((pin) => pin.version !== undefined && pin.version !== version)\n\t\t\t.map((pin) =>\n\t\t\t\twarning(\n\t\t\t\t\t`${pin.file} starts asana-gate ${pin.version ?? \"?\"}; this is ${version}: run \"asana-gate init --agent …\" to update it`,\n\t\t\t\t),\n\t\t\t),\n\t];\n}\n\nexport { AGENT_NAMES, agentsNamed, auditAgentFiles, refreshSkillCopies, wireAgents };\nexport type { Agent };\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"api-Cd3qXjya.mjs","names":[],"sources":["../src/cli/api.ts"],"sourcesContent":["// Copyright 2026 Shinsuke Mori\n// SPDX-License-Identifier: Apache-2.0\n\nimport { parseArgs } from \"node:util\";\n\nimport { isHttpMethod } from \"../gate/router.ts\";\nimport { GATED_OPTIONS, UsageError, usageRows } from \"./context.ts\";\nimport { readData } from \"./flags.ts\";\nimport { runGated } from \"./run.ts\";\n\nconst API_OPTIONS = {\n\tquery: {\n\t\ttype: \"string\",\n\t\tshort: \"q\",\n\t\tmultiple: true,\n\t\tplaceholder: \"<key=value>\",\n\t\tdescription: \"Query parameter (repeatable; opt_fields takes a comma list)\",\n\t},\n\tdata: {\n\t\ttype: \"string\",\n\t\tshort: \"d\",\n\t\tplaceholder: \"<json>\",\n\t\tdescription: 'Request body as JSON (\"@file\" reads a file, \"-\" reads stdin)',\n\t},\n\t...GATED_OPTIONS,\n} as const;\n\nconst USAGE = `Usage: asana-gate api <METHOD> <path> [options]\n\nCall any Asana REST operation through the policy. The path is the part below\n/api/1.0, for example /tasks/123 or /workspaces/456/tasks/search.\n\nThe response body is always printed as JSON.\n\nOptions:\n${usageRows(API_OPTIONS)}\n\nExamples:\n asana-gate api GET /tasks/123 -q opt_fields=name,completed\n asana-gate api POST /tasks -d '{\"name\": \"Write docs\", \"projects\": [\"123\"]}'\n asana-gate api PUT /tasks/123 -d @task.json`;\n\n/** Runs `asana-gate api <METHOD> <path>`. */\nasync function runApi(argv: readonly string[]): Promise<number> {\n\tconst { values, positionals } = parseArgs({\n\t\targs: [...argv],\n\t\toptions: API_OPTIONS,\n\t\tallowPositionals: true,\n\t\tstrict: true,\n\t});\n\tif (values.help === true) {\n\t\tconsole.log(USAGE);\n\t\treturn 0;\n\t}\n\tconst [methodArg, path] = positionals;\n\tconst method = methodArg?.toUpperCase();\n\tif (method === undefined || path === undefined || !isHttpMethod(method)) {\n\t\tthrow new UsageError(`api needs a method (GET, POST, PUT, DELETE) and a path\\n\\n${USAGE}`);\n\t}\n\tconst query: Record<string, string> = {};\n\tfor (const pair of values.query ?? []) {\n\t\tconst separator = pair.indexOf(\"=\");\n\t\tif (separator === -1) {\n\t\t\tthrow new UsageError(`--query expects key=value, got \"${pair}\"`);\n\t\t}\n\t\tquery[pair.slice(0, separator)] = pair.slice(separator + 1);\n\t}\n\tconst body =\n\t\tvalues.data === undefined ? undefined : await readData(values.data, values.directory);\n\treturn runGated(() => ({ method, path, query, body }), { ...values, json: true });\n}\n\nexport { runApi };\n"],"mappings":";;;;;;AAUA,MAAM,cAAc;CACnB,OAAO;EACN,MAAM;EACN,OAAO;EACP,UAAU;EACV,aAAa;EACb,aAAa;CACd;CACA,MAAM;EACL,MAAM;EACN,OAAO;EACP,aAAa;EACb,aAAa;CACd;CACA,GAAG;AACJ;AAEA,MAAM,QAAQ;;;;;;;;EAQZ,UAAU,WAAW,EAAE;;;;;;;AAQzB,eAAe,OAAO,MAA0C;CAC/D,MAAM,EAAE,QAAQ,gBAAgB,UAAU;EACzC,MAAM,CAAC,GAAG,IAAI;EACd,SAAS;EACT,kBAAkB;EAClB,QAAQ;CACT,CAAC;CACD,IAAI,OAAO,SAAS,MAAM;EACzB,QAAQ,IAAI,KAAK;EACjB,OAAO;CACR;CACA,MAAM,CAAC,WAAW,QAAQ;CAC1B,MAAM,SAAS,WAAW,YAAY;CACtC,IAAI,WAAW,KAAA,KAAa,SAAS,KAAA,KAAa,CAAC,aAAa,MAAM,GACrE,MAAM,IAAI,WAAW,6DAA6D,OAAO;CAE1F,MAAM,QAAgC,CAAC;CACvC,KAAK,MAAM,QAAQ,OAAO,SAAS,CAAC,GAAG;EACtC,MAAM,YAAY,KAAK,QAAQ,GAAG;EAClC,IAAI,cAAc,IACjB,MAAM,IAAI,WAAW,mCAAmC,KAAK,EAAE;EAEhE,MAAM,KAAK,MAAM,GAAG,SAAS,KAAK,KAAK,MAAM,YAAY,CAAC;CAC3D;CACA,MAAM,OACL,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,MAAM,SAAS,OAAO,MAAM,OAAO,SAAS;CACrF,OAAO,gBAAgB;EAAE;EAAQ;EAAM;EAAO;CAAK,IAAI;EAAE,GAAG;EAAQ,MAAM;CAAK,CAAC;AACjF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"check-bGxfSyj4.mjs","names":[],"sources":["../src/cli/check.ts"],"sourcesContent":["// Copyright 2026 Shinsuke Mori\n// SPDX-License-Identifier: Apache-2.0\n\nimport { parseArgs } from \"node:util\";\n\nimport { FactsLoader } from \"../gate/facts.ts\";\nimport { cacheEntries } from \"../gate/listing-cache.ts\";\nimport { type CompiledConstraints, type CompiledRule, PolicyError } from \"../policy/types.ts\";\nimport { auditAgentFiles } from \"./agent.ts\";\nimport { auditEnvironment, auditReferences, policyWarnings } from \"./audit.ts\";\nimport { COMMON_OPTIONS, usageRows } from \"./context.ts\";\nimport { describeUser } from \"./identity.ts\";\nimport { loadPolicy } from \"./policy.ts\";\nimport { createContext } from \"./session.ts\";\n\nconst USAGE = `Usage: asana-gate check [options]\n\nValidate the settings and the policy: the token works, every name resolves,\nevery gid the rules name still exists in the workspace, and the cache and log\ndirectories can be written. Problems make the command fail (exit code 1);\nwarnings do not.\n\nOptions:\n${usageRows(COMMON_OPTIONS)}`;\n\n/** `resource.member` for every member a per-resource map or set names, with custom fields by name. */\nfunction membersOf(\n\tlabels: ReadonlyMap<string, string>,\n\tbyResource: ReadonlyMap<string, ReadonlyMap<string, unknown> | ReadonlySet<string>>,\n): string[] {\n\treturn [...byResource].flatMap(([resource, members]) =>\n\t\t[...(members instanceof Set ? members : members.keys())].map((key: string) => {\n\t\t\tconst label = labels.get(key);\n\t\t\treturn label === undefined ? `${resource}.${key}` : `${resource} ${label}`;\n\t\t}),\n\t);\n}\n\nfunction describeConstraints(constraints: CompiledConstraints): string {\n\tconst clauses: [string, string[]][] = [\n\t\t[\"require\", membersOf(constraints.labels, constraints.require)],\n\t\t[\"apply\", membersOf(constraints.labels, constraints.apply)],\n\t\t[\"forbid\", membersOf(constraints.labels, constraints.forbid)],\n\t\t[\"redact\", membersOf(constraints.labels, constraints.redact)],\n\t\t[\"limit\", [...constraints.limit].map(([action, l]) => `${action} ${l.max} per ${l.per}`)],\n\t\t[\"confirm\", [...constraints.confirm]],\n\t];\n\treturn clauses\n\t\t.filter(([, items]) => items.length > 0)\n\t\t.map(([name, items]) => `${name} ${items.join(\", \")}`)\n\t\t.join(\"; \");\n}\n\nfunction describeActions(rule: CompiledRule): string {\n\tconst actions = [...rule.actions];\n\treturn actions.length > 6\n\t\t? `${actions.slice(0, 6).join(\", \")}, … (${actions.length} actions)`\n\t\t: actions.join(\", \");\n}\n\nfunction describeRule(rule: CompiledRule): string {\n\tconst where = rule.raw.where === undefined ? \"workspace\" : JSON.stringify(rule.raw.where);\n\tconst shown =\n\t\trule.constraints === undefined ? describeActions(rule) : describeConstraints(rule.constraints);\n\treturn ` rules[${rule.index}] ${rule.effect.padEnd(5)} level ${rule.specificity.level}.${rule.specificity.cross} where ${where}\\n ${shown}`;\n}\n\n/** A policy that names something Asana does not have is a problem `check` reports (exit 1), not a usage error. */\nfunction unresolved(error: unknown): undefined {\n\tif (!(error instanceof PolicyError)) {\n\t\tthrow error;\n\t}\n\tconsole.log(`problem: ${error.message}`);\n\tconsole.log(\"1 problems, 0 warnings\");\n\treturn undefined;\n}\n\nasync function runCheck(argv: readonly string[], version: string): Promise<number> {\n\tconst { values } = parseArgs({ args: [...argv], options: COMMON_OPTIONS, strict: true });\n\tif (values.help === true) {\n\t\tconsole.log(USAGE);\n\t\treturn 0;\n\t}\n\tconst context = await createContext(values);\n\tconst policy = await loadPolicy(context).catch(unresolved);\n\tif (policy === undefined) {\n\t\treturn 1;\n\t}\n\tconst { settings, projectDir } = context.loaded;\n\tconst loader = new FactsLoader({ client: context.client, policy, logger: context.logger });\n\tconst [references, environment, agent, listings] = await Promise.all([\n\t\tauditReferences(policy, loader),\n\t\tauditEnvironment(context),\n\t\tprojectDir === undefined ? [] : auditAgentFiles(projectDir, version),\n\t\tsettings.cache.enabled ? cacheEntries(settings.cache.dir) : 0,\n\t]);\n\tconst cache = settings.cache.enabled ? `${settings.cache.dir} (${listings} listings)` : \"off\";\n\tconsole.log(`policy: ${settings.policy ?? \"?\"}`);\n\tconsole.log(`workspace: ${policy.workspaceName} (${policy.workspace})`);\n\tconsole.log(`token: ${describeUser(policy.me)} from ${context.token.source}`);\n\tconsole.log(`cache: ${cache}`);\n\tconsole.log(`log: ${context.log.file ?? \"stderr only\"}`);\n\tconsole.log(`rules: ${policy.rules.length} compiled statements`);\n\tfor (const rule of policy.rules) {\n\t\tconsole.log(describeRule(rule));\n\t}\n\tconsole.log(`references: ${references.checked} objects the rules name, checked against Asana`);\n\tconst findings = [...policyWarnings(policy), ...references.findings, ...environment, ...agent];\n\tfor (const finding of findings) {\n\t\tconsole.log(`${finding.level}: ${finding.text}`);\n\t}\n\tconst problems = findings.filter((finding) => finding.level === \"problem\").length;\n\tconst warnings = findings.length - problems;\n\tconsole.log(findings.length === 0 ? \"ok\" : `${problems} problems, ${warnings} warnings`);\n\treturn problems === 0 ? 0 : 1;\n}\n\nexport { runCheck };\n"],"mappings":"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"}