@prestack/thread 0.1.20 → 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -0
- package/dist/core/descend.d.ts +2 -0
- package/dist/core/descend.js +12 -0
- package/dist/core/descend.ts +13 -1
- package/dist/core/rows.d.ts +5 -0
- package/dist/core/rows.js +45 -0
- package/dist/core/rows.ts +47 -0
- package/dist/integrations/cli.d.ts +3 -9
- package/dist/integrations/cli.js +27 -26
- package/dist/integrations/cli.ts +29 -38
- package/dist/integrations/declared.d.ts +8 -0
- package/dist/integrations/declared.js +22 -0
- package/dist/integrations/declared.ts +34 -0
- package/dist/integrations/target.d.ts +1 -1
- package/dist/integrations/target.js +20 -6
- package/dist/integrations/target.ts +22 -6
- package/dist/integrity/generators/publish.js +2 -1
- package/dist/integrity/generators/publish.ts +2 -1
- package/dist/integrity/slopnators/sl_unlisted_program.js +2 -2
- package/dist/integrity/slopnators/sl_unlisted_program.ts +2 -2
- package/dist/operations/generators/compile.d.ts +21 -0
- package/dist/operations/generators/compile.js +1 -1
- package/dist/operations/generators/compile.ts +1 -1
- package/dist/operations/generators/permits.d.ts +2 -1
- package/dist/operations/generators/permits.js +52 -47
- package/dist/operations/generators/permits.ts +66 -61
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,89 @@
|
|
|
1
1
|
# @prestack/thread
|
|
2
2
|
|
|
3
|
+
## 0.1.20
|
|
4
|
+
|
|
5
|
+
it only added, so everything built against the last one still works.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `invoked` now exports `core/invoked#BUILT`.
|
|
10
|
+
- `programs` now exports `integrations/cli#COPY_AT`.
|
|
11
|
+
|
|
12
|
+
<!-- release 0.1.20 -->
|
|
13
|
+
<!-- holds
|
|
14
|
+
actor 3fe4eda6870f core/actor#Env:e97761857593 core/actor#ENVIRONMENT:c63ce331e66a core/actor#Environment:0e63440f7ed9 core/actor#Actor:da6a0a4f6d1a core/actor#PUBLIC_ROLE:0708d38af082 core/actor#ANONYMOUS:7aac93520d5f
|
|
15
|
+
attach cc938d84a7dd core/attach#packageOf:95b5fff25591 core/attach#Appending:a9e0459b54b9 core/attach#Writing:be521774d91f core/attach#Attaching:8fc9a32f36f5 core/attach#UnattachableError:c0915e9e2ee4 core/attach#StillADependencyError:92c932b34a0a core/attach#StillDeclaredError:055509e3ed65 core/attach#DependencyRingError:2efe6ca0a2a5 core/attach#TakenFileError:58b4ac596857 core/attach#UnthreadedError:cb4f87163654 core/attach#attaches:253b1b546924 core/attach#behind:35e21849c546 core/attach#attach:dbf8043d1045 core/attach#detach:90e9cd60ecd5 core/attach#ATTACH:8b0b999ca5c9
|
|
16
|
+
build-writer 9028c2674ff9 derivation/generators/build#bundle:2f856621a0ad derivation/generators/build#declared:f833228cb868 derivation/generators/build#wanted:ca9066873bf3
|
|
17
|
+
capability-writer c145dbe8aa50 operations/generators/capability#Surfaced:9c1e29582b29 operations/generators/capability#defaulted:480e1df52387 operations/generators/capability#derive:8c0fb0e63099 operations/generators/capability#reaching:96904eb501f6 operations/generators/capability#asArray:7fe62b04f8cb
|
|
18
|
+
chain e14ea2ab54de core/chain#generators:714b6bd5de71 core/chain#offers:6dadb72b44b4 core/chain#RAN:8720636fbac7 core/chain#REFUSED_BY:3eae304480a7 core/chain#batched:97a8754eeaf1 core/chain#settling:ca839ad0fbd3
|
|
19
|
+
commits 269f05bc2f60
|
|
20
|
+
compile-writer 645a30cc2081 operations/generators/compile#parts:a2c39cf9feb9 operations/generators/compile#compile:2fb552595d35
|
|
21
|
+
compiler-scope c78718dff992
|
|
22
|
+
condition ec0eb30e786a core/condition#COMPARE_OPS:6a33a047f408 core/condition#CompareOp:97849b9d273e core/condition#AGGREGATIONS:d213c6d7a137 core/condition#ACTOR_FACTS:752e796b5c97 core/condition#AGO:09aa52ab5287 core/condition#Operand:451f00cec049 core/condition#Condition:29dadf7cfd50 core/condition#walkOperands:9aa17730b2ab core/condition#mentionsActor:793e52b424e1 core/condition#agoSeconds:5d4cb8909c84 core/condition#satisfies:32daa43a97f3 core/condition#CONDITION_ANSWERS:a4a5fdf48aa5 core/condition#conditioned:3b65b55a7c83 core/condition#said:d7feb19d07d8
|
|
23
|
+
constraint-shape 6d751f2bf6c8 integrity/constraint#Sourced:7a4a750b4216 integrity/constraint#Proof:ed7d660baa12 integrity/constraint#shown:6522e6fa1dbf integrity/constraint#Constraint:9f751237a030 integrity/constraint#CONSTRAINTS:a99a22a9f325
|
|
24
|
+
core-attach cc938d84a7dd core/attach#packageOf:95b5fff25591 core/attach#Appending:a9e0459b54b9 core/attach#Writing:be521774d91f core/attach#Attaching:8fc9a32f36f5 core/attach#UnattachableError:c0915e9e2ee4 core/attach#StillADependencyError:92c932b34a0a core/attach#StillDeclaredError:055509e3ed65 core/attach#DependencyRingError:2efe6ca0a2a5 core/attach#TakenFileError:58b4ac596857 core/attach#UnthreadedError:cb4f87163654 core/attach#attaches:253b1b546924 core/attach#behind:35e21849c546 core/attach#attach:dbf8043d1045 core/attach#detach:90e9cd60ecd5 core/attach#ATTACH:8b0b999ca5c9
|
|
25
|
+
core-capabilities 8bfaef776075 operations/capabilities#SURFACES:462a2a1a7395 operations/capabilities#Surface:f6edd9874bdb operations/capabilities#isSurface:b576dba589f2 operations/capabilities#MEANS:3658f1c4eb73 operations/capabilities#DEFAULTS_AT:aa7e7135823b operations/capabilities#UNSTATED:cfcca264f76f operations/capabilities#Defaults:a9803c2f1af4 operations/capabilities#CAPABILITIES_AT:b837276e2b3f operations/capabilities#CLIENT_AT:69106f1a9d39 operations/capabilities#DISPATCHING_AT:79217c5a5a98 operations/capabilities#COMPILED:8a2e68c66250 operations/capabilities#CHECKED_AT:894587e29088 operations/capabilities#REACHING_AT:cd2556536e41 operations/capabilities#ACTOR_AT:81a568a0fb0c operations/capabilities#routeAt:b80bb4b90b70 operations/capabilities#ROUTE:7dec5eba4788 operations/capabilities#inboundAt:1a4583a141f1 operations/capabilities#OPENAPI_AT:d6b86d9cb07d operations/capabilities#MCP_AT:5b46a2eec16c operations/capabilities#Capability:878bfe369e2b operations/capabilities#reachable:40d77d9b3ba7 operations/capabilities#switched:a654a4b88939
|
|
26
|
+
core-dispatch 1874eb1e70a7 operations/dispatch#DISPATCH_AT:4e8f2c0639bf operations/dispatch#dispatched:b8a8e12c37e2
|
|
27
|
+
databases 1a5345f17774 integrations/pglite#shapeOf:c5582022770c integrations/pglite#Kept:6057152b4e6e integrations/pglite#Stood:aa41216d75b6 integrations/pglite#standing:78b2926e3f47 integrations/pglite#storing:4bbdae21bdcc
|
|
28
|
+
derivation-attach 33ee19bee9e7 derivation/attach#ATTACH:8b0b999ca5c9
|
|
29
|
+
derived-check d0b098621843 derivation/generators/check#CheckStatus:3d5184654de8 derivation/generators/check#FileCheck:5fc2fc17d9dc derivation/generators/check#CheckReport:0a85b0b7a552 derivation/generators/check#ReadFile:bfe47da3146a derivation/generators/check#CheckOptions:12047b27ac13 derivation/generators/check#checkGenerated:303b484f0191 derivation/generators/check#formatCheckReport:f1ffd8d71128 derivation/generators/check#detectHandEdits:4cb9374c9dec
|
|
30
|
+
descend 98b2f1c8f190 core/descend#ROOT:16475c413846 core/descend#TREE:16475c413846 core/descend#THREAD_AT:16475c413846 core/descend#unkept:c4b11ba631c2 core/descend#LISTS:4bc9c06ef52b core/descend#ROW_LISTS:c9d0aa651f7b core/descend#Row:b97aa507e223 core/descend#Pass:6d224c4baa3b core/descend#Finding:59d032ea6dfc core/descend#under:9d2961e6c891 core/descend#sources:3ccbfc44dc32 core/descend#configured:08dd6fe94449 core/descend#hosting:03773213bb0d core/descend#uncompiled:e6cc5d02da1f core/descend#read:5b91d50130a7 core/descend#shapesNamed:b7e8c501d5a3 core/descend#threading:4203b54a8ba4 core/descend#shapeFields:c90f90e89613 core/descend#Field:3cff13ab8ec4 core/descend#listShape:de887cd9f0d5 core/descend#listFields:0ac02ba9a2d7 core/descend#rowShape:de887cd9f0d5 core/descend#nodesIn:0e1ab44ef9ff core/descend#reached:3ccbfc44dc32 core/descend#forget:a3965c1dfabe core/descend#descend:cb2c0f44b0be
|
|
31
|
+
descent-check 21b078209d19 integrity/check-threads#ROOT:fed419935721 integrity/check-threads#THREAD_AT:ad73a49b2e42 integrity/check-threads#TREE:b1b38c62f173 integrity/check-threads#descend:e424ec88ff49 integrity/check-threads#Finding:59d032ea6dfc integrity/check-threads#Pass:ebdf8cc00bc4 integrity/check-threads#trackedFiles:3ccbfc44dc32 integrity/check-threads#unthreaded:461b6e326ac7 integrity/check-threads#twiceParented:e96bea943ec4 integrity/check-threads#refusals:f9f72d575f28
|
|
32
|
+
determinism 30bc0a11b902 derivation/generators/determinism#GeneratedFile:1f5dc83a87cd derivation/generators/determinism#sortedBy:f08908497eb1 derivation/generators/determinism#compare:8ad383dc8043 derivation/generators/determinism#sortedEntries:61aff6982b60 derivation/generators/determinism#bodyHash:155def245510 derivation/generators/determinism#withHeader:1561e9fea045 derivation/generators/determinism#ParsedFile:078b3aa626c3 derivation/generators/determinism#parseGenerated:e4beb7be1f99 derivation/generators/determinism#lines:c0f235ccf1c6 derivation/generators/determinism#tsString:8a273616993f derivation/generators/determinism#stableJson:5d314875cc3d derivation/generators/determinism#pascal:ff8fa0760be2 derivation/generators/determinism#camel:ff8fa0760be2
|
|
33
|
+
docs-writer 3133175d51ef
|
|
34
|
+
error-catalogue e8bbd9220d52 core/errors/catalogue#AuthUnauthenticated:7e24f688d95d core/errors/catalogue#AuthInvalidCredentials:6e9c9b5413b8 core/errors/catalogue#AuthTokenExpired:3d4e6245d4fc core/errors/catalogue#AuthTokenReused:1f9440e9b282 core/errors/catalogue#AuthSessionRevoked:85af3a32bd03 core/errors/catalogue#AuthDenied:2f7a896f225a core/errors/catalogue#QuotaExceeded:62810e277123 core/errors/catalogue#QuotaReservationExpired:eec8b5e6df5e core/errors/catalogue#RateLimitExceeded:90b8438d32ae core/errors/catalogue#FeatureNotInPlan:304ce3f7caf9 core/errors/catalogue#DbNotFound:60f59203aba5 core/errors/catalogue#DbConstraintViolation:9c00c2863608 core/errors/catalogue#DbAlreadyExists:3b70497d8a74 core/errors/catalogue#DbConflict:2b62291e50de core/errors/catalogue#DbMigrationChecksumMismatch:85390d325334 core/errors/catalogue#DbDestructiveWithoutDryRun:3a740a2a33eb core/errors/catalogue#DbRoundTripBudgetExceeded:163a19f0d8d6 core/errors/catalogue#DbCursorInvalid:ce7f9cc9c08f core/errors/catalogue#DbCursorExpired:3d2f1df512e8 core/errors/catalogue#WorkflowNodeFailed:1c4b5a94fe09 core/errors/catalogue#WorkflowInvalidTransition:fdcb1b51d4ac core/errors/catalogue#WorkflowCompensationFailed:c75b034c6ac9 core/errors/catalogue#WorkflowAlreadyRunning:fbb480d80e00 core/errors/catalogue#QueueJobFailed:27181968a2f5 core/errors/catalogue#QueueDlqExhausted:6aea1c485aa9 core/errors/catalogue#AiProviderUnavailable:81a440a67d2b core/errors/catalogue#AiSchemaValidationFailed:af8093c663e0 core/errors/catalogue#AiToolNotInMask:e146b0a15718 core/errors/catalogue#AiNodeCapExceeded:fe1c6e7a515b core/errors/catalogue#SearchIndexFailed:7dfae99b2c09 core/errors/catalogue#SearchQueryInvalid:0d12d8cbd08f core/errors/catalogue#CommsChannelKindUndeclared:aee44b376a96 core/errors/catalogue#CommsChannelKindUndescribed:3d9b33eab1a5 core/errors/catalogue#CommsChannelKindUnlabelled:d133c17b625f core/errors/catalogue#CommsChannelKindUndocumented:ba7825c59599 core/errors/catalogue#CommsChannelKindDuplicate:bfb8e5a55815 core/errors/catalogue#ConfigInvalid:d60b61c23be3 core/errors/catalogue#ConfigMissingEnv:b9894f249713 core/errors/catalogue#ConfigSecretInPublicVar:52d6b7523d93 core/errors/catalogue#ConfigCredentialInvalid:3b2093f17fe9 core/errors/catalogue#ConfigScopeMissing:ae883fc18dd8 core/errors/catalogue#ConfigResourceNotFound:adfbe73a76e9 core/errors/catalogue#ConfigDestinationIncompatible:7c8f1af25018 core/errors/catalogue#ConfigBlocksExit:89e1100f3501 core/errors/catalogue#NetTimeout:b58c1472a696 core/errors/catalogue#NetUpstreamUnavailable:f0970ddb2b72 core/errors/catalogue#NetDestinationRefused:bc6fbc18e2d8 core/errors/catalogue#InternalUnexpected:928b73a76ab6 core/errors/catalogue#InternalNotImplemented:c5c6590041d7 core/errors/catalogue#InternalInvalidArgument:ce6701313197 core/errors/catalogue#PLATFORM_ERRORS:99af67671495 core/errors/catalogue#PlatformErrorCode:8f4f69419324
|
|
35
|
+
error-classes 9e5a171ecfc9 core/errors/classes#ErrorClassDef:f86478155103 core/errors/classes#ERROR_CLASSES:edfbdd775e5f core/errors/classes#ErrorClass:76fd5e188a3d core/errors/classes#ERROR_CLASS_NAMES:74c194ba25bd core/errors/classes#classDef:7d0a82d47941
|
|
36
|
+
error-namespaces e446f70fbaf3 core/errors/namespaces#NAMESPACES:e337ac1a0dcc core/errors/namespaces#Namespace:605585a58c10 core/errors/namespaces#ErrorCode:9c332e778de1
|
|
37
|
+
error-results e57bf4578348 operations/error-results#errorDefForResult:d20408abb638 operations/error-results#platformErrorForResult:cfa19576d3d2
|
|
38
|
+
error-shape 88996a2a97a2 core/errors/error#ErrorCode:b1b889e0a6a2 core/errors/error#ErrorDef:7cbf5075cdfe core/errors/error#DefineErrorInput:26ba65e1ba53 core/errors/error#PlatformErrorInit:46fb5f54ad40 core/errors/error#PlatformError:cb9f313b940e core/errors/error#isPlatformError:54c7e704b130 core/errors/error#ErrorFactory:ac8e16652a4c core/errors/error#DuplicateErrorCodeError:c2e0d4b9a453 core/errors/error#ErrorCatalog:2d6513801aad core/errors/error#catalog:6f8193fbf011 core/errors/error#defineError:b63127ff92f5
|
|
39
|
+
files 0e27f37485f0 integrations/disk#Answering:ac82a4270dab integrations/disk#Kind:f5387f9bb6ed integrations/disk#Listed:78797afdac99 integrations/disk#Measured:9298c8f4b3ff integrations/disk#Ran:b6a7c95e785f integrations/disk#CHANNEL:aed3e27aa991 integrations/disk#FOLDER:e95be41b2cdc integrations/disk#answeredBy:c00c834376b3 integrations/disk#across:c4b11ba631c2 integrations/disk#beyond:c4b11ba631c2 integrations/disk#attached:f8c2780ce4f6 integrations/disk#here:f971b85d3d6d integrations/disk#kind:485fa3d1c1c6 integrations/disk#existsSync:219e8de5f523 integrations/disk#readFileSync:84627dee3e2a integrations/disk#writeFileSync:b65098c20781 integrations/disk#createFileSync:a37d24a0bcc9 integrations/disk#Named:a490c22afabe integrations/disk#readdirSync:2fab39d45004 integrations/disk#Held:488919ee8a4c integrations/disk#statSync:658893a15fb6 integrations/disk#rmSync:92d8fa578550 integrations/disk#rmdirSync:9473a29789e7 integrations/disk#renameSync:9c9fbadb45e6 integrations/disk#appendFileSync:ecfd24b4e865 integrations/disk#realpathSync:626005f54fe3 integrations/disk#HERE:b5fa160c6f41 integrations/disk#standing:860b93996daf
|
|
40
|
+
finding 9058cbe2ee32 core/finding#Finding:180d780f4cd9 core/finding#forbids:019885a2a7da core/finding#runChecker:bea68acae26f
|
|
41
|
+
gate-writer 9f32b3557c07
|
|
42
|
+
glossary-shape 8e609bb71c20 knowledge/glossary#Glossary:e30f4c6fe581
|
|
43
|
+
glossary-writer fb212157b8ef
|
|
44
|
+
grant-shape 3faea89db7de operations/access#PERMITS_AT:747bdea9514c operations/access#declaredWords:5a76b6349900 operations/access#undeclared:f8a1498208ca operations/access#Declaring:d425aa11e994 operations/access#Caller:e84d64e1d650 operations/access#keyIn:9590087fcf75 operations/access#declaredCallers:935aee93abaa operations/access#Grant:e7cec0376200 operations/access#opensToEverybody:10368b21fa22 operations/access#grantedTwice:563aa26b055e operations/access#unanswerable:563aa26b055e
|
|
45
|
+
http 7393c692f6a1 integrations/https#HTTP_CALL_ACTION:b90d08fc2104 integrations/https#HttpNotConfiguredError:cb4f87163654 integrations/https#OutwardTransportError:b169a7a9de9a integrations/https#refusedPath:7ece79538abe integrations/https#outwardUrl:ab5ee055ae1c integrations/https#HttpOptions:d44a8302e1a2 integrations/https#STREAMED:0f44419eff19 integrations/https#TOLD:ca7940b4fc66 integrations/https#called:e21f31899fb4 integrations/https#sendingHttp:945b8b045042 integrations/https#RecordedCall:318c0983fea1 integrations/https#ScriptedAnswer:9f4273f0ade9 integrations/https#Scripted:6df9ac9d9f15 integrations/https#recordingHttp:fc2ad46f8053
|
|
46
|
+
init 1cc74e78bbcd core/init#TREE:0b34eb8c6947 core/init#ROOT:23a226909662 core/init#SHAPED:babaddbfd35d core/init#AlreadyThreadedError:6b783660d574 core/init#COMPILER:09b3efa678f5 core/init#MANIFEST:495fdf585250 core/init#REGISTRY:16475c413846 core/init#IGNORED:16475c413846 core/init#ignored:15de269b224c core/init#compiler:15de269b224c core/init#root:383996e16a82 core/init#init:8121415e87a8
|
|
47
|
+
integrations-attach f0c1aa199681 integrations/attach#CONCEPTS:7a75843a03cf integrations/attach#ATTACH:8b0b999ca5c9
|
|
48
|
+
integrity-attach 209d320f0218 integrity/attach#ATTACH:8b0b999ca5c9
|
|
49
|
+
invoked c2f326b79fa8 core/invoked#invoked:9133dcc091f3 core/invoked#SOURCE:e43353c41f9b core/invoked#BESIDE:95b5fff25591 core/invoked#BUILT:74c647d3ad5c core/invoked#LOADER:4de2138e3a11 core/invoked#CLI:4de2138e3a11 core/invoked#REFUSED:5cbef15de1fd core/invoked#shared:4820653ff101 core/invoked#exit:a631d3ee5cd5 core/invoked#refusal:51d097295f50
|
|
50
|
+
issues-writer 66733ec4dec8
|
|
51
|
+
knowledge-attach cfc36ad0f082 knowledge/attach#ATTACH:8b0b999ca5c9
|
|
52
|
+
lint 1ca80d4d7bad integrity/lint#ruleMessage:cbd1b8bbcf00 integrity/lint#agentInstructions:3ccbfc44dc32 integrity/lint#defineRule:d391a4a1f3aa integrity/lint#defineRules:8bfd1bf6cfa5 integrity/lint#ruleRule:466d7d9ccaa3 integrity/lint#ruleRules:b7cc8a626183 integrity/lint#ruleSeverities:4506861e89ae integrity/lint#plugin:948c4ffe9079 integrity/lint#default:af79bdaf6dee integrity/lint#rules:f3a0aef9ed97 integrity/lint#ruleDeclarations:30516a9f1aa2 integrity/lint#RuleViolation:31a1a1e48e80 integrity/lint#RuleRunner:bbf72f90b110 integrity/lint#theRules:89139ffca783
|
|
53
|
+
lsp-bin f592352bce19
|
|
54
|
+
lsp-diagnostics 49801c4b0424 integrity/lsp/diagnostics#DiagnosticSource:d08c813cf00a integrity/lsp/diagnostics#repoSource:dff5c2ce8d38 integrity/lsp/diagnostics#ERROR:d674d8e65aca integrity/lsp/diagnostics#WARNING:00a4f8869ab3 integrity/lsp/diagnostics#Position:46e0a3561d8b integrity/lsp/diagnostics#Diagnostic:ae6f64604dbe integrity/lsp/diagnostics#SOURCE_NAME:2514d79dbd06 integrity/lsp/diagnostics#toDiagnostic:fcae9032abb1 integrity/lsp/diagnostics#report:0dbedc0cd91b
|
|
55
|
+
lsp-findings 72f7d80645c0 integrity/lsp/findings#At:f235cb016ba3 integrity/lsp/findings#Finding:7d5c3a039f29 integrity/lsp/findings#detailOf:c2c587190fb0 integrity/lsp/findings#anchorIn:a250e5899ebf integrity/lsp/findings#locate:3793c6d451b7 integrity/lsp/findings#headOf:1a535cdf8f10 integrity/lsp/findings#rangeOf:f398dcb2f343
|
|
56
|
+
lsp-lint 87850cd24e7c integrity/lsp/lint#isLintable:fd3e0e886f7d integrity/lsp/lint#LINT_CONFIG:82d55ccf289a integrity/lsp/lint#LintUnavailableError:f8f16a4068e3 integrity/lsp/lint#lintFindings:8fa9b43d2fa3
|
|
57
|
+
lsp-protocol d0ad8650307b integrity/lsp/protocol#RpcMessage:50bff985f883 integrity/lsp/protocol#METHOD_NOT_FOUND:ada3d6776590 integrity/lsp/protocol#encode:f00f8f2ab7bb integrity/lsp/protocol#MalformedMessageError:f8f16a4068e3 integrity/lsp/protocol#MessageBuffer:b1e528cf49fb
|
|
58
|
+
lsp-server a66c663b032d integrity/lsp/server#ServerOptions:b2f4aaebe993 integrity/lsp/server#LspServer:5fa4c9448c6f
|
|
59
|
+
operation-nodes 20b2da81c3ba operations/nodes#Node:2112c57d9bb8 operations/nodes#Held:0ec1b9f302e4 operations/nodes#STOPPED:5cbef15de1fd operations/nodes#stopped:2f6d794b907c operations/nodes#nd_read:7bebde547b8e operations/nodes#nd_action:65eae62feaaa operations/nodes#nd_branch:2c5b4a591cd3 operations/nodes#nd_each:bae680443754 operations/nodes#nd_parallel:bfa84c79ec03 operations/nodes#nd_repeat:3966ebc9c7c8 operations/nodes#nd_stop:61b8668ab2a5
|
|
60
|
+
operation-shape 76f2a87e0f89 operations/operations#OPERATIONS_FILE:e46dfbcf462b operations/operations#TRIALS_AT:aaf352faa5b3 operations/operations#NODES_FILE:210e774203a3 operations/operations#MEMBERS_LIST:23961436d339 operations/operations#Reaching:deebde0237b4 operations/operations#Opened:eb6571a8c1bb operations/operations#Reads:f8c3a12083b7 operations/operations#WINDOWS:89b1baaceb71 operations/operations#Window:c777511a8ae1 operations/operations#Allowance:04d9eb029682 operations/operations#Counting:7e197fa63f26 operations/operations#Operation:f6d6334481b9 operations/operations#OperationMember:cf2297306e4b operations/operations#OPERATIONS:7e34107beaa8
|
|
61
|
+
operations-attach 80bcb52911fd operations/attach#TAKES:6cddee9943a2 operations/attach#WOVEN:a99aa29866b3 operations/attach#said:c89bb33d7607 operations/attach#ATTACH:8b0b999ca5c9
|
|
62
|
+
permits-writer 357585245554
|
|
63
|
+
programs 22d93a63455e integrations/cli#Starting:960e2047c9fb integrations/cli#starts:0e1bf71a8735 integrations/cli#started:cd7548fe9f9c integrations/cli#handed:d687c7041310 integrations/cli#Holding:39f4bf3d6d9e integrations/cli#Held:aa0aeeffb516 integrations/cli#releases:a3965c1dfabe integrations/cli#claims:3aa4752f056f integrations/cli#programFor:bd904f4e38b2 integrations/cli#SIGNING:8cd5f4b56b1b integrations/cli#signing:15de269b224c integrations/cli#PROGRAM:16475c413846 integrations/cli#COPIES:16475c413846 integrations/cli#COPY_AT:16475c413846 integrations/cli#running:ea5213e21370 integrations/cli#Expansion:fbb6d3ec7c7f integrations/cli#expansions:ebec34e2d4e0 integrations/cli#calls:979f9d21a871 integrations/cli#LOCKFILES:0d3bc577e11b integrations/cli#manager:45f7b3a950fa integrations/cli#adding:8c0a5aa2eb4b integrations/cli#needing:6ad702835da5 integrations/cli#installing:38eeb450b217
|
|
64
|
+
publish-writer 58a8d9768b1b
|
|
65
|
+
read-command b963de5ab710
|
|
66
|
+
release-shape 969a84467fb1 derivation/release#PREFIXES:b8074240fbd0 derivation/release#KINDS:48b5fc802be2 derivation/release#Written:c43100ae39af derivation/release#WRITES:e54e839a5471 derivation/release#LISTENS:58f03905ca9e derivation/release#SAID:5bd0783b90d3 derivation/release#kindOf:4176df8c51b9 derivation/release#WRITTEN_BY:9173a6988956 derivation/release#CHECKED_BY:da31b0e1d991
|
|
67
|
+
release-writer 2ed92545845c derivation/generators/release#CHECKED_BY:50e734bb9f42 derivation/generators/release#WRITES:b89e55dbc69c derivation/generators/release#made:ea0890697a77
|
|
68
|
+
result 9f5e98a1c646 operations/result#ResultCode:2c9cb831da2e operations/result#FailureIdentity:8af44679ea20 operations/result#Result:51fa3d37b70f operations/result#ok:012b7060c34a operations/result#fail:5787814702d4 operations/result#ValidationError:8056c1ea409e
|
|
69
|
+
round 5f921eb9c8f9
|
|
70
|
+
rows 6194da5f7cb9 core/rows#Bounds:9f96256b89fa core/rows#inCode:3aa8ca939e44 core/rows#matched:efe81f54e0c4 core/rows#listBounds:3adc84a88226 core/rows#nestedBounds:eecf676136a9 core/rows#holdsRow:745a20ac8a94 core/rows#seededAt:483fd49afaa5 core/rows#rowsIn:98b8583dd419 core/rows#withRow:dcc57512f05d core/rows#withSeed:dd37a3bf5b3b core/rows#withRequires:d11efd3851ea core/rows#seedsIn:2de54e168233 core/rows#afterRow:6c07ac3f763a core/rows#quoted:7cb4ec66102d core/rows#valuesIn:84f1cf0a2b48 core/rows#unread:a2c39cf9feb9 core/rows#STATED:3c39f854eb6a core/rows#reconciled:36df6a2bfcce core/rows#fieldIn:13b49f086cce core/rows#withField:7c52e0fd3d24 core/rows#withTopField:6ac3873438fe core/rows#withoutField:04bf213eb8dc core/rows#withoutRow:ecc4a8d269f9 core/rows#marked:ca0a5bc98816 core/rows#showing:2d45570925a8
|
|
71
|
+
scope 5ac2ae9efe74 core/scope#ORGANISATION:8510114ffd9e core/scope#THING:2514d79dbd06 core/scope#NAMED:c33cb60b8e33 core/scope#named:72b4c80878b8 core/scope#idOf:3ab7154bd91a core/scope#ours:ab9daad14f31 core/scope#installed:f0f987abd6f9
|
|
72
|
+
sealed-store 53b4c569beaa integrations/vault#VAULT_DIR:5dd2b28d7cef integrations/vault#SEALED_NAME:4eaaac010b8c integrations/vault#KEY_NAME:065de823d162 integrations/vault#SEALED_AT:548d924665e3 integrations/vault#KEY_AT:2bcb12622e0d integrations/vault#ALGORITHM:84a84e44a5a1 integrations/vault#KEY_BYTES:95940045d335 integrations/vault#keyOf:71ea2ee0c552 integrations/vault#keyed:878e72b78d7b integrations/vault#seal:48aead05fdcd integrations/vault#sealedIn:d0d2e1cc0461 integrations/vault#opened:fea1d83b295a integrations/vault#unseal:e06ef898eab9 integrations/vault#IGNORES:4de2138e3a11
|
|
73
|
+
secret a544a5e4fa77 integrations/secret#SECRECY:0fd167bfea16 integrations/secret#SAID:7b6a22f69118 integrations/secret#Vault:8dc7e8d666b8 integrations/secret#Secret:7cbfaeada097 integrations/secret#secrecyOf:53c866c6d50d integrations/secret#isServerOnly:14af671c09c3 integrations/secret#unclassified:3f18056f2160 integrations/secret#valued:3f18056f2160
|
|
74
|
+
seed-writer e007d91fb3a6 operations/generators/seed#quoted:b3a2bd470cb2 operations/generators/seed#beside:6c0fa306492b operations/generators/seed#runtime:b909738618a0 operations/generators/seed#types:2aee6c512ee7 operations/generators/seed#builtFrom:3b21d7bfce78 operations/generators/seed#operations:69e0b4d6cf2d operations/generators/seed#problem:44d3a33067da operations/generators/seed#blockIn:4aa89e8da0ca operations/generators/seed#scaffold:d58c01b2574a operations/generators/seed#nodeText:f7813131ffee operations/generators/seed#seed:9a4c29314682
|
|
75
|
+
shape 079cfa1542bf core/thread#Quote:34b9cab8ecec core/thread#Threaded:aa8a41b1903e core/thread#Member:2112c57d9bb8 core/thread#PREFIXES:263416accca5
|
|
76
|
+
slopnator 13296d2b3935 integrity/slopnators/sl_broken_lineage#slopnator:42fb769c73ec integrity/slopnators/sl_declared_elsewhere#slopnator:42fb769c73ec integrity/slopnators/sl_derived_drift#Derivation:a7cc81c002ff integrity/slopnators/sl_derived_drift#derivations:f46b8572fa7c integrity/slopnators/sl_derived_drift#slopnator:42fb769c73ec integrity/slopnators/sl_door_in_a_node#slopnator:42fb769c73ec integrity/slopnators/sl_hardcoded_style#slopnator:42fb769c73ec integrity/slopnators/sl_inert_island#slopnator:42fb769c73ec integrity/slopnators/sl_inert_slopnator#slopnator:42fb769c73ec integrity/slopnators/sl_missing_row#slopnator:42fb769c73ec integrity/slopnators/sl_no_barrel#slopnator:42fb769c73ec integrity/slopnators/sl_no_child_process#slopnator:42fb769c73ec integrity/slopnators/sl_no_comment#slopnator:42fb769c73ec integrity/slopnators/sl_no_dispatch_bypass#slopnator:42fb769c73ec integrity/slopnators/sl_no_import_cycle#slopnator:42fb769c73ec integrity/slopnators/sl_no_such_command#slopnator:42fb769c73ec integrity/slopnators/sl_only_takes_a_literal#slopnator:42fb769c73ec integrity/slopnators/sl_outside_an_operation#slopnator:42fb769c73ec integrity/slopnators/sl_screen_holds_only_declared#slopnator:42fb769c73ec integrity/slopnators/sl_secret_literal#slopnator:42fb769c73ec integrity/slopnators/sl_stale_path#slopnator:42fb769c73ec integrity/slopnators/sl_twice_meant#slopnator:42fb769c73ec integrity/slopnators/sl_twice_parented#slopnator:42fb769c73ec integrity/slopnators/sl_undeclared_crossing#DOORWAY:7291424d5e4c integrity/slopnators/sl_undeclared_crossing#HANDED_TO:43e1dac30e33 integrity/slopnators/sl_undeclared_crossing#judging:73bfee6bcfe2 integrity/slopnators/sl_undeclared_crossing#slopnator:42fb769c73ec integrity/slopnators/sl_undeclared_destination#slopnator:42fb769c73ec integrity/slopnators/sl_undeclared_element#slopnator:42fb769c73ec integrity/slopnators/sl_undeclared_list#slopnator:42fb769c73ec integrity/slopnators/sl_undeclared_node#slopnator:42fb769c73ec integrity/slopnators/sl_undeclared_operation#slopnator:42fb769c73ec integrity/slopnators/sl_undeclared_variant#slopnator:42fb769c73ec integrity/slopnators/sl_undeclared_webhook#slopnator:42fb769c73ec integrity/slopnators/sl_underived_route#slopnator:42fb769c73ec integrity/slopnators/sl_undescribed#slopnator:42fb769c73ec integrity/slopnators/sl_ungoverned_island#slopnator:42fb769c73ec integrity/slopnators/sl_unlisted_program#slopnator:42fb769c73ec integrity/slopnators/sl_unnamed_island#slopnator:42fb769c73ec integrity/slopnators/sl_unpaired_member#slopnator:42fb769c73ec integrity/slopnators/sl_unpaired_slopnator#slopnator:42fb769c73ec integrity/slopnators/sl_unprefixed_member#slopnator:42fb769c73ec integrity/slopnators/sl_unthreaded#Reach:ee1c5ae840ce integrity/slopnators/sl_unthreaded#Meaning:eb5d28d0d101 integrity/slopnators/sl_unthreaded#here:7186c669fd80 integrity/slopnators/sl_unthreaded#atsIn:2a22e0fd79d4 integrity/slopnators/sl_unthreaded#rowsIn:e0b6bdfd102e integrity/slopnators/sl_unthreaded#Governed:26751a8a4a1c integrity/slopnators/sl_unthreaded#governedBy:7fd12eca7c1b integrity/slopnators/sl_unthreaded#filesGoverned:65cdfbe444d1 integrity/slopnators/sl_unthreaded#foldersGoverned:65cdfbe444d1 integrity/slopnators/sl_unthreaded#governs:a4fad74ada50 integrity/slopnators/sl_unthreaded#Declared:28a6c94b90c6 integrity/slopnators/sl_unthreaded#canonical:74c647d3ad5c integrity/slopnators/sl_unthreaded#islandsDeclared:16048ec0c690 integrity/slopnators/sl_unthreaded#declaresIsland:f3daaa415aee integrity/slopnators/sl_unthreaded#meaningsIn:53683e6a54b6 integrity/slopnators/sl_unthreaded#Index:1768b6501864 integrity/slopnators/sl_unthreaded#index:b914d00e9d0f integrity/slopnators/sl_unthreaded#forget:a3965c1dfabe integrity/slopnators/sl_unthreaded#threaded:2b0e40c55bac integrity/slopnators/sl_unthreaded#parses:df7c6aede8b6 integrity/slopnators/sl_unthreaded#unreadable:cb6cf51129a6 integrity/slopnators/sl_unthreaded#names:0096812bd8bb integrity/slopnators/sl_unthreaded#slopnator:42fb769c73ec integrity/slopnators/sl_untranslated_key#slopnator:42fb769c73ec integrity/slopnators/sl_unvaulted_secret#slopnator:42fb769c73ec integrity/slopnators/sl_unversioned#slopnator:42fb769c73ec
|
|
77
|
+
slopnator-shape 51d078034457 integrity/slopnator#NOT_WRITTEN:5cbef15de1fd integrity/slopnator#SHIPPED:16475c413846 integrity/slopnator#SEEDED:16475c413846 integrity/slopnator#ROOT:16475c413846 integrity/slopnator#SlopnatorContext:d2a635854c3c integrity/slopnator#Spoken:e2c874045414 integrity/slopnator#Proves:0369cb81daa2 integrity/slopnator#Reads:b81a76c9cc9a integrity/slopnator#Reading:76ea63cd70a7 integrity/slopnator#Running:25cbab8e340a integrity/slopnator#Slopnator:ad0ae14e5f13 integrity/slopnator#Visiting:9af67a68f078 integrity/slopnator#reads:e851af39272f integrity/slopnator#visits:6e4f7f5deee8 integrity/slopnator#sweeps:e851af39272f integrity/slopnator#Byproduct:1b8a6fb06159 integrity/slopnator#slopnatorName:c452dd2bdbbc integrity/slopnator#region:637499d76201 integrity/slopnator#derivedHere:7186fd9fd284 integrity/slopnator#subject:e8d0ab22f1d4 integrity/slopnator#governs:91c49fcb7fdf integrity/slopnator#UnloadableSlopnatorError:9028dcb4c5ec integrity/slopnator#UnreadableRulesError:b60942b119f0 integrity/slopnator#load:5eaf126b2fda integrity/slopnator#proofsOf:763e7a5e9da3 integrity/slopnator#scaffold:15de269b224c integrity/slopnator#write:5c9de9c9d484 integrity/slopnator#onDisk:d463041c43a5 integrity/slopnator#named:c6a6a92894dc integrity/slopnator#rules:13ef34c2acc6 integrity/slopnator#seeds:a6a029998d40 integrity/slopnator#GENERALLY:baedbff8be54 integrity/slopnator#declaring:7229d8fb559f integrity/slopnator#declareSeeded:e732adf1e1e2
|
|
78
|
+
sweep-walk ef2bdac3afa7 integrity/sweep#visit:9b8811eccd92 integrity/sweep#Caught:5b4dba207f58 integrity/sweep#tracked:d463041c43a5 integrity/sweep#sweep:c668e953efb7
|
|
79
|
+
target-shape 6a040b114324 integrations/target#REACH:7f6cf3225ee3 integrations/target#Reach:28718a29ebbb integrations/target#ADDRESS:0ac7d4249d53 integrations/target#Addressed:83aeecdb60d8 integrations/target#Holds:dc775c87554b integrations/target#HOLDS:191fd51c8c5e integrations/target#SAID:cbb49ee60a17 integrations/target#OPENS:49659340ec1b integrations/target#Kind:8f9d1230cc55 integrations/target#Listed:60ef88b9766a integrations/target#Measured:ba8fd66caf68 integrations/target#Answering:94596db14850 integrations/target#Attached:5db9e59588f2 integrations/target#ORDERS:18b2c6e76a2b integrations/target#Order:a8b50f8b7042 integrations/target#Answer:eabf66413c91 integrations/target#Recorded:fc9fb7439786 integrations/target#How:29dc321843d4 integrations/target#Ran:8a9d78d05850 integrations/target#Running:b730520aa405 integrations/target#Calling:8a1fa971be64 integrations/target#HttpMethod:52ada6a3365a integrations/target#HttpRequest:a2d4c8dbe75f integrations/target#HttpResponse:b56874e51801 integrations/target#Http:834fa96f4955 integrations/target#Row:6f5edf17a61c integrations/target#PropertyValue:4885bb975ac1 integrations/target#isRow:539dcd1c4a4b integrations/target#ReadField:99e67343fe70 integrations/target#FieldList:83120b2166e7 integrations/target#Store:3e01b6e1529c integrations/target#Transactional:c8d08d0622c4 integrations/target#isTransactional:1170f66cd9b8 integrations/target#Integration:d851a497f22c integrations/target#Target:be9e72681022 integrations/target#Webhook:859980501775 integrations/target#Call:6f9ff3b7255b integrations/target#CALL_PREFIX:471df1e09d10 integrations/target#fills:ebc8be09b0a4 integrations/target#reachOf:20d02de80d4c integrations/target#standsHere:44e3d70360f8 integrations/target#holdsOf:901a78c9a0d2 integrations/target#requirable:babe69707585 integrations/target#driverOf:6e977f406f5c integrations/target#addressOf:586d8e0c699d integrations/target#credentialsOf:cba586002fb2 integrations/target#servesBrowser:88b5a2eb80b0 integrations/target#unreachable:3fd2b82d0e99 integrations/target#LOCKFILES:f79c78e2421b integrations/target#PACKAGER:5c86349b8352 integrations/target#managerOf:2fb3ef208615 integrations/target#programOf:0438b85eb0d1 integrations/target#unlisted:95b5fff25591 integrations/target#misnamed:b92bbf30de70 integrations/target#misaccepted:4bb2e3fb0b7d integrations/target#placedAt:040d115c24d8 integrations/target#placed:8954a87a6efd integrations/target#unaddressed:2dff7cf19161 integrations/target#unheld:2dff7cf19161 integrations/target#unanswered:a6d304c26fd3 integrations/target#unplaced:840ddd6855b4 integrations/target#refusals:acca65833de8 integrations/target#targetOf:822f8d420b17
|
|
80
|
+
tree 296438e3beb4 core/tree#FOLDER:2027dbad6ffb core/tree#Tree:8f338d863404 core/tree#UnthreadedRepositoryError:9ee18e1932c0 core/tree#folder:15de269b224c core/tree#findTree:49ec72a1c670 core/tree#strayFiles:495876581332 core/tree#inTree:9763add68f9f
|
|
81
|
+
trial-runner 79913cceed92 operations/generators/trial#TRIALS_AT:48cf5b1696fb operations/generators/trial#Scenario:7e6b3edabc0c operations/generators/trial#Trial:ec5363988c79 operations/generators/trial#Outcome:0b6ac6861c30 operations/generators/trial#Run:4064695a5df2 operations/generators/trial#runScenario:7e1119843a5d operations/generators/trial#scenariosFor:807a80dc6acb operations/generators/trial#compared:c81d29fd44b2 operations/generators/trial#unproven:27bd1e31789b operations/generators/trial#record:2ba585ade9fe
|
|
82
|
+
trial-writer 0bb31c131a9b integrity/generators/trial#Scenario:cec489475009 integrity/generators/trial#Trial:0ed5a9870dc8 integrity/generators/trial#Derivation:5542c019485a integrity/generators/trial#Outcome:4a336cfdb388 integrity/generators/trial#Run:4e6160f4a4fd integrity/generators/trial#probeAt:cbd1b8bbcf00 integrity/generators/trial#deriveTrials:801b86fffdcc integrity/generators/trial#runTrial:9d8f24783d10 integrity/generators/trial#crossed:ccfbf430e6ea integrity/generators/trial#runTrials:0b4ce7fbb41d
|
|
83
|
+
types df0eae11185b core/types#VALUE_TYPES:9d3af11975a0 core/types#ValueType:de0a55f12333 core/types#KEYBOARDS:187f8f1b5fef core/types#Keyboard:0f9fcadff185 core/types#ENTRY_MODES:6937aa450f33 core/types#EntryMode:619a8cf61463 core/types#Checked:3be2f12a6aae core/types#held:ecda2d49d546 core/types#refused:6c4e70ea8940 core/types#Facts:f94c9b180191 core/types#Format:f0fc652558a7 core/types#stripControl:ffc10711842d core/types#BOUNDED:ae1a8dd96249 core/types#FORMATS:a879ae389a3c core/types#formatsOf:1dda69cdbc5b core/types#formatNamed:2007301c8e1b core/types#plainFormat:f683a8a755a5 core/types#formatFor:36746cc1a7ad core/types#checkValue:c4d6bf4e05e4 core/types#showValue:68bfeaa86be4
|
|
84
|
+
vault-writer 8d195f000c9c
|
|
85
|
+
-->
|
|
86
|
+
|
|
3
87
|
## 0.1.19
|
|
4
88
|
|
|
5
89
|
what it exports is untouched and its code moved.
|
package/dist/core/descend.d.ts
CHANGED
|
@@ -60,6 +60,7 @@ export declare function shapeFields(named: string, inside?: string): readonly {
|
|
|
60
60
|
readonly worded: boolean;
|
|
61
61
|
readonly guide: string;
|
|
62
62
|
readonly record: readonly string[];
|
|
63
|
+
readonly objects: boolean;
|
|
63
64
|
}[];
|
|
64
65
|
export interface Field {
|
|
65
66
|
readonly name: string;
|
|
@@ -70,6 +71,7 @@ export interface Field {
|
|
|
70
71
|
readonly worded: boolean;
|
|
71
72
|
readonly guide: string;
|
|
72
73
|
readonly record: readonly string[];
|
|
74
|
+
readonly objects: boolean;
|
|
73
75
|
}
|
|
74
76
|
export declare function listShape(at: string, list: string): string | undefined;
|
|
75
77
|
export declare function listFields(at: string, list: string, within?: number): readonly Field[];
|
package/dist/core/descend.js
CHANGED
|
@@ -422,6 +422,7 @@ export function shapeFields(named, inside) {
|
|
|
422
422
|
worded: (kind.isUnion() ? kind.types : [kind]).some((each) => (each.flags & ts.TypeFlags.StringLike) !== 0),
|
|
423
423
|
guide: ts.displayPartsToString(one.getDocumentationComment(checker)).trim(),
|
|
424
424
|
record: recordOf(checker, kind),
|
|
425
|
+
objects: objectsOf(checker, kind),
|
|
425
426
|
};
|
|
426
427
|
});
|
|
427
428
|
}
|
|
@@ -497,12 +498,23 @@ export function listFields(at, list, within) {
|
|
|
497
498
|
worded: worded(kind),
|
|
498
499
|
guide: ts.displayPartsToString(one.getDocumentationComment(checker)).trim(),
|
|
499
500
|
record: recordOf(checker, kind),
|
|
501
|
+
objects: objectsOf(checker, kind),
|
|
500
502
|
};
|
|
501
503
|
});
|
|
502
504
|
}
|
|
503
505
|
function elementOf(checker, type) {
|
|
504
506
|
return checker.getIndexTypeOfType(type, ts.IndexKind.Number) ?? type;
|
|
505
507
|
}
|
|
508
|
+
function objectsOf(checker, type) {
|
|
509
|
+
for (const each of type.isUnion() ? type.types : [type]) {
|
|
510
|
+
if ((each.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null | ts.TypeFlags.StringLike)) !== 0)
|
|
511
|
+
continue;
|
|
512
|
+
const held = checker.getIndexTypeOfType(each, ts.IndexKind.Number) ?? each;
|
|
513
|
+
if ((held.isUnion() ? held.types : [held]).every((one) => (one.flags & ts.TypeFlags.Object) !== 0))
|
|
514
|
+
return true;
|
|
515
|
+
}
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
506
518
|
function recordOf(checker, type) {
|
|
507
519
|
for (const each of type.isUnion() ? type.types : [type]) {
|
|
508
520
|
if ((each.flags & ts.TypeFlags.StringLike) !== 0 || checker.getIndexTypeOfType(each, ts.IndexKind.Number) === undefined)
|
package/dist/core/descend.ts
CHANGED
|
@@ -446,7 +446,7 @@ export function threading(): ReadonlySet<string> {
|
|
|
446
446
|
export function shapeFields(
|
|
447
447
|
named: string,
|
|
448
448
|
inside?: string,
|
|
449
|
-
): readonly { readonly name: string; readonly required: boolean; readonly list: boolean; readonly map: boolean; readonly worded: boolean; readonly guide: string; readonly record: readonly string[] }[] {
|
|
449
|
+
): readonly { readonly name: string; readonly required: boolean; readonly list: boolean; readonly map: boolean; readonly worded: boolean; readonly guide: string; readonly record: readonly string[]; readonly objects: boolean }[] {
|
|
450
450
|
const { program, checker } = compiled()
|
|
451
451
|
for (const at of [...sources(), ...imported(program)]) {
|
|
452
452
|
if (!SOURCE.test(at)) continue
|
|
@@ -484,6 +484,7 @@ export function shapeFields(
|
|
|
484
484
|
worded: (kind.isUnion() ? kind.types : [kind]).some((each) => (each.flags & ts.TypeFlags.StringLike) !== 0),
|
|
485
485
|
guide: ts.displayPartsToString(one.getDocumentationComment(checker)).trim(),
|
|
486
486
|
record: recordOf(checker, kind),
|
|
487
|
+
objects: objectsOf(checker, kind),
|
|
487
488
|
}
|
|
488
489
|
})
|
|
489
490
|
}
|
|
@@ -500,6 +501,7 @@ export interface Field {
|
|
|
500
501
|
readonly worded: boolean
|
|
501
502
|
readonly guide: string
|
|
502
503
|
readonly record: readonly string[]
|
|
504
|
+
readonly objects: boolean
|
|
503
505
|
}
|
|
504
506
|
|
|
505
507
|
function elementAt(at: string, list: string, within?: number): { readonly type: ts.Type; readonly node: ts.Node } | undefined {
|
|
@@ -578,6 +580,7 @@ export function listFields(at: string, list: string, within?: number): readonly
|
|
|
578
580
|
worded: worded(kind),
|
|
579
581
|
guide: ts.displayPartsToString(one.getDocumentationComment(checker)).trim(),
|
|
580
582
|
record: recordOf(checker, kind),
|
|
583
|
+
objects: objectsOf(checker, kind),
|
|
581
584
|
}
|
|
582
585
|
})
|
|
583
586
|
}
|
|
@@ -586,6 +589,15 @@ function elementOf(checker: ts.TypeChecker, type: ts.Type): ts.Type {
|
|
|
586
589
|
return checker.getIndexTypeOfType(type, ts.IndexKind.Number) ?? type
|
|
587
590
|
}
|
|
588
591
|
|
|
592
|
+
function objectsOf(checker: ts.TypeChecker, type: ts.Type): boolean {
|
|
593
|
+
for (const each of type.isUnion() ? type.types : [type]) {
|
|
594
|
+
if ((each.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null | ts.TypeFlags.StringLike)) !== 0) continue
|
|
595
|
+
const held = checker.getIndexTypeOfType(each, ts.IndexKind.Number) ?? each
|
|
596
|
+
if ((held.isUnion() ? held.types : [held]).every((one) => (one.flags & ts.TypeFlags.Object) !== 0)) return true
|
|
597
|
+
}
|
|
598
|
+
return false
|
|
599
|
+
}
|
|
600
|
+
|
|
589
601
|
function recordOf(checker: ts.TypeChecker, type: ts.Type): readonly string[] {
|
|
590
602
|
for (const each of type.isUnion() ? type.types : [type]) {
|
|
591
603
|
if ((each.flags & ts.TypeFlags.StringLike) !== 0 || checker.getIndexTypeOfType(each, ts.IndexKind.Number) === undefined) continue
|
package/dist/core/rows.d.ts
CHANGED
|
@@ -29,4 +29,9 @@ export declare function withTopField(text: string, field: string, value: string)
|
|
|
29
29
|
export declare function withoutField(text: string, where: Bounds, id: string, field: string): string;
|
|
30
30
|
export declare function withoutRow(text: string, where: Bounds, id: string): string;
|
|
31
31
|
export declare function marked(parts: readonly string[]): string;
|
|
32
|
+
export declare const markOf: (row: object) => string;
|
|
33
|
+
export declare function literalIn(text: string): unknown;
|
|
34
|
+
export declare const unreadable: (held: unknown) => boolean;
|
|
35
|
+
export declare function written(held: unknown, pad: string): string;
|
|
36
|
+
export declare function withWritten(text: string, where: Bounds, id: string, field: string, held: unknown): string | undefined;
|
|
32
37
|
export declare function showing(row: object, only?: readonly string[]): string;
|
package/dist/core/rows.js
CHANGED
|
@@ -432,6 +432,51 @@ const lines = (held, pad) => {
|
|
|
432
432
|
export function marked(parts) {
|
|
433
433
|
return createHash('sha256').update(parts.join('\n')).digest('hex').slice(0, 6);
|
|
434
434
|
}
|
|
435
|
+
export const markOf = (row) => {
|
|
436
|
+
const held = row;
|
|
437
|
+
return marked([
|
|
438
|
+
typeof held.id === 'string' ? held.id : '',
|
|
439
|
+
typeof held.at === 'string' ? held.at : '',
|
|
440
|
+
typeof held.describes === 'string' ? held.describes : '',
|
|
441
|
+
held.version === undefined ? '' : String(held.version),
|
|
442
|
+
]);
|
|
443
|
+
};
|
|
444
|
+
const WHOLE = /^-?[0-9][0-9_]*(?:\.[0-9]+)?$/;
|
|
445
|
+
export function literalIn(text) {
|
|
446
|
+
const said = text.trim();
|
|
447
|
+
if (WHOLE.test(said))
|
|
448
|
+
return Number(said.split('_').join(''));
|
|
449
|
+
const held = taken(`const held = ${said}`);
|
|
450
|
+
return held.length === 1 && held[0]?.[1] !== UNREAD ? held[0]?.[1] : UNREAD;
|
|
451
|
+
}
|
|
452
|
+
export const unreadable = (held) => held === UNREAD;
|
|
453
|
+
const BARE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
454
|
+
function inline(held) {
|
|
455
|
+
if (typeof held === 'string')
|
|
456
|
+
return quoted(held);
|
|
457
|
+
if (Array.isArray(held))
|
|
458
|
+
return `[${held.map(inline).join(', ')}]`;
|
|
459
|
+
if (held !== null && typeof held === 'object') {
|
|
460
|
+
const pairs = Object.entries(held).map(([key, one]) => `${BARE.test(key) ? key : quoted(key)}: ${inline(one)}`);
|
|
461
|
+
return pairs.length === 0 ? '{}' : `{ ${pairs.join(', ')} }`;
|
|
462
|
+
}
|
|
463
|
+
return String(held);
|
|
464
|
+
}
|
|
465
|
+
export function written(held, pad) {
|
|
466
|
+
if (!Array.isArray(held) || held.every((one) => typeof one !== 'object' || one === null))
|
|
467
|
+
return inline(held);
|
|
468
|
+
return ['[', ...held.map((one) => `${pad} ${inline(one)},`), `${pad}]`].join('\n');
|
|
469
|
+
}
|
|
470
|
+
export function withWritten(text, where, id, field, held) {
|
|
471
|
+
const row = rowAt(text, where, id);
|
|
472
|
+
if (row === undefined)
|
|
473
|
+
return undefined;
|
|
474
|
+
const named = row.properties.find((one) => ts.isPropertyAssignment(one) && keyed(one) === field) ?? row.properties.at(-1);
|
|
475
|
+
if (named === undefined)
|
|
476
|
+
return undefined;
|
|
477
|
+
const line = text.lastIndexOf('\n', named.getStart()) + 1;
|
|
478
|
+
return fieldOn(text, row, field, written(held, /^[ \t]*/.exec(text.slice(line))?.[0] ?? ''));
|
|
479
|
+
}
|
|
435
480
|
export function showing(row, only = []) {
|
|
436
481
|
const held = row;
|
|
437
482
|
const keys = Object.keys(held);
|
package/dist/core/rows.ts
CHANGED
|
@@ -441,6 +441,53 @@ export function marked(parts: readonly string[]): string {
|
|
|
441
441
|
return createHash('sha256').update(parts.join('\n')).digest('hex').slice(0, 6)
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
+
export const markOf = (row: object): string => {
|
|
445
|
+
const held = row as { readonly id?: unknown; readonly at?: unknown; readonly describes?: unknown; readonly version?: unknown }
|
|
446
|
+
return marked([
|
|
447
|
+
typeof held.id === 'string' ? held.id : '',
|
|
448
|
+
typeof held.at === 'string' ? held.at : '',
|
|
449
|
+
typeof held.describes === 'string' ? held.describes : '',
|
|
450
|
+
held.version === undefined ? '' : String(held.version),
|
|
451
|
+
])
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const WHOLE = /^-?[0-9][0-9_]*(?:\.[0-9]+)?$/
|
|
455
|
+
|
|
456
|
+
export function literalIn(text: string): unknown {
|
|
457
|
+
const said = text.trim()
|
|
458
|
+
if (WHOLE.test(said)) return Number(said.split('_').join(''))
|
|
459
|
+
const held = taken(`const held = ${said}`)
|
|
460
|
+
return held.length === 1 && held[0]?.[1] !== UNREAD ? held[0]?.[1] : UNREAD
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export const unreadable = (held: unknown): boolean => held === UNREAD
|
|
464
|
+
|
|
465
|
+
const BARE = /^[A-Za-z_$][A-Za-z0-9_$]*$/
|
|
466
|
+
|
|
467
|
+
function inline(held: unknown): string {
|
|
468
|
+
if (typeof held === 'string') return quoted(held)
|
|
469
|
+
if (Array.isArray(held)) return `[${held.map(inline).join(', ')}]`
|
|
470
|
+
if (held !== null && typeof held === 'object') {
|
|
471
|
+
const pairs = Object.entries(held).map(([key, one]) => `${BARE.test(key) ? key : quoted(key)}: ${inline(one)}`)
|
|
472
|
+
return pairs.length === 0 ? '{}' : `{ ${pairs.join(', ')} }`
|
|
473
|
+
}
|
|
474
|
+
return String(held)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export function written(held: unknown, pad: string): string {
|
|
478
|
+
if (!Array.isArray(held) || held.every((one) => typeof one !== 'object' || one === null)) return inline(held)
|
|
479
|
+
return ['[', ...held.map((one) => `${pad} ${inline(one)},`), `${pad}]`].join('\n')
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
export function withWritten(text: string, where: Bounds, id: string, field: string, held: unknown): string | undefined {
|
|
483
|
+
const row = rowAt(text, where, id)
|
|
484
|
+
if (row === undefined) return undefined
|
|
485
|
+
const named = row.properties.find((one) => ts.isPropertyAssignment(one) && keyed(one) === field) ?? row.properties.at(-1)
|
|
486
|
+
if (named === undefined) return undefined
|
|
487
|
+
const line = text.lastIndexOf('\n', named.getStart()) + 1
|
|
488
|
+
return fieldOn(text, row, field, written(held, /^[ \t]*/.exec(text.slice(line))?.[0] ?? ''))
|
|
489
|
+
}
|
|
490
|
+
|
|
444
491
|
export function showing(row: object, only: readonly string[] = []): string {
|
|
445
492
|
const held = row as Record<string, unknown>
|
|
446
493
|
const keys = Object.keys(held)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LOCKFILES, type
|
|
1
|
+
import { LOCKFILES, type Ran, type Running } from '../integrations/target.ts';
|
|
2
2
|
export interface Starting {
|
|
3
3
|
readonly at?: string;
|
|
4
4
|
readonly shows?: boolean | 'errors' | 'tee';
|
|
@@ -19,20 +19,14 @@ export interface Held {
|
|
|
19
19
|
}
|
|
20
20
|
export declare function releases(): void;
|
|
21
21
|
export declare function claims(root: string, runs: string): Held;
|
|
22
|
-
export declare function programFor(name: string, at: string): string;
|
|
22
|
+
export declare function programFor(name: string, at: string): readonly string[];
|
|
23
23
|
export declare const SIGNING = "THREAD_RECEIPTS_KEY";
|
|
24
24
|
export declare function signing(): string;
|
|
25
25
|
export declare const PROGRAM: string;
|
|
26
26
|
export declare const COPIES: string;
|
|
27
27
|
export declare const COPY_AT: string;
|
|
28
28
|
export declare function running(name: string, subcommands: Readonly<Record<string, string>>, at: string): Running;
|
|
29
|
-
export
|
|
30
|
-
readonly program: string;
|
|
31
|
-
readonly target: Target;
|
|
32
|
-
readonly calls: readonly Call[];
|
|
33
|
-
}
|
|
34
|
-
export declare function expansions(at: string): readonly Expansion[];
|
|
35
|
-
export declare function calls(target: string, at: string): Running;
|
|
29
|
+
export { calls, expansions, type Expansion } from '../integrations/declared.ts';
|
|
36
30
|
export { LOCKFILES };
|
|
37
31
|
export declare const manager: (into: string) => string;
|
|
38
32
|
export declare function adding(into: string): readonly [string, string];
|
package/dist/integrations/cli.js
CHANGED
|
@@ -6,11 +6,10 @@ import { allowedNodeEnvironmentFlags, env, execPath, kill, pid, stderr, stdout }
|
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { CHANNEL, FOLDER, across, attached, createFileSync, existsSync, here, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from '../integrations/disk.js';
|
|
8
8
|
import { VAULT_DIR } from '../integrations/vault.js';
|
|
9
|
-
import {
|
|
9
|
+
import { LOCKFILES, ORDERS, PACKAGER, REACH, managerOf, programOf, unlisted } from '../integrations/target.js';
|
|
10
10
|
import { BESIDE, CLI } from '../core/invoked.js';
|
|
11
|
-
import { valuesIn } from '../core/rows.js';
|
|
12
11
|
import { THING } from '../core/scope.js';
|
|
13
|
-
import { findTree
|
|
12
|
+
import { findTree } from '../core/tree.js';
|
|
14
13
|
const answered = (went) => ({
|
|
15
14
|
there: went.error === undefined,
|
|
16
15
|
ok: went.status === 0,
|
|
@@ -141,7 +140,7 @@ export function claims(root, runs) {
|
|
|
141
140
|
return { by: { pid: 0, runs: '', since: Date.now() } };
|
|
142
141
|
}
|
|
143
142
|
export function programFor(name, at) {
|
|
144
|
-
const found = programOf(name, at, existsSync);
|
|
143
|
+
const found = programOf(name, at, existsSync, (path) => readFileSync(path, 'utf8'));
|
|
145
144
|
if (found === undefined)
|
|
146
145
|
throw new Error(unlisted(name));
|
|
147
146
|
return found;
|
|
@@ -246,6 +245,23 @@ const READS = new Set(Object.entries(ORDERS).filter(([order, answer]) => order =
|
|
|
246
245
|
function kept(one, asked, held) {
|
|
247
246
|
if (READS.has(asked.order) && held.answered !== 'refused')
|
|
248
247
|
one.known.set(told(asked), held);
|
|
248
|
+
if (asked.order !== 'write' || held.answered !== ORDERS.write)
|
|
249
|
+
return;
|
|
250
|
+
one.known.set(told({ order: 'read', at: asked.at }), { answered: 'read', said: asked.said ?? '' });
|
|
251
|
+
one.known.set(told({ order: 'kind', at: asked.at }), { answered: 'kind', found: 'file' });
|
|
252
|
+
}
|
|
253
|
+
const CHANGES = new Set(['write', 'remove']);
|
|
254
|
+
const within = (at, under) => under === '' || at === under || at.startsWith(under + '/');
|
|
255
|
+
function forgets(one, asked) {
|
|
256
|
+
if (!CHANGES.has(asked.order)) {
|
|
257
|
+
one.known.clear();
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
for (const key of [...one.known.keys()]) {
|
|
261
|
+
const [order = '', at = ''] = JSON.parse(key);
|
|
262
|
+
if (order === 'real' || within(at, asked.at) || within(asked.at, at))
|
|
263
|
+
one.known.delete(key);
|
|
264
|
+
}
|
|
249
265
|
}
|
|
250
266
|
const plainly = (one) => one.order + ' ' + (one.at === '' ? '.' : one.at);
|
|
251
267
|
const outside = (root, at) => {
|
|
@@ -300,7 +316,7 @@ function watching(one) {
|
|
|
300
316
|
continue;
|
|
301
317
|
}
|
|
302
318
|
if (!READS.has(asked.order))
|
|
303
|
-
one
|
|
319
|
+
forgets(one, asked);
|
|
304
320
|
const due = one.replaying.shift();
|
|
305
321
|
if (due !== undefined) {
|
|
306
322
|
if (told(due.order) === told(asked)) {
|
|
@@ -427,31 +443,15 @@ export function running(name, subcommands, at) {
|
|
|
427
443
|
? async (args, shows, within, how) => served(word, args, within, how)
|
|
428
444
|
: async (args, shows, within, how) => {
|
|
429
445
|
const where = how?.at ?? at;
|
|
430
|
-
const program = programFor(name, where);
|
|
446
|
+
const [program = '', ...lead] = programFor(name, where);
|
|
431
447
|
if ((shows ?? false) !== false)
|
|
432
|
-
return handed(where, program, [word, ...args], shows ?? false, within, how?.hears);
|
|
433
|
-
return await started(program, [word, ...args], { at: where, ...(within === undefined ? {} : { within }), ...(how?.hears === undefined ? {} : { hears: how.hears }) });
|
|
448
|
+
return handed(where, program, [...lead, word, ...args], shows ?? false, within, how?.hears);
|
|
449
|
+
return await started(program, [...lead, word, ...args], { at: where, ...(within === undefined ? {} : { within }), ...(how?.hears === undefined ? {} : { hears: how.hears }) });
|
|
434
450
|
};
|
|
435
451
|
}
|
|
436
452
|
return out;
|
|
437
453
|
}
|
|
438
|
-
|
|
439
|
-
const path = inTree(findTree(at), 'targets.ts');
|
|
440
|
-
return existsSync(path) ? valuesIn(readFileSync(path, 'utf8')) : {};
|
|
441
|
-
}
|
|
442
|
-
export function expansions(at) {
|
|
443
|
-
const held = sheet(at);
|
|
444
|
-
return (held.TARGETS ?? [])
|
|
445
|
-
.filter((one) => one.id.startsWith(REACH.cli))
|
|
446
|
-
.map((one) => ({ program: one.id.slice(REACH.cli.length), target: one, calls: (held.CALLS ?? []).filter((each) => each.of === one.id) }));
|
|
447
|
-
}
|
|
448
|
-
export function calls(target, at) {
|
|
449
|
-
const named = {};
|
|
450
|
-
for (const one of sheet(at).CALLS ?? [])
|
|
451
|
-
if (one.of === target)
|
|
452
|
-
named[one.id.replace(CALL_PREFIX, '')] = one.path;
|
|
453
|
-
return running(target.replace(REACH.cli, ''), named, at);
|
|
454
|
-
}
|
|
454
|
+
export { calls, expansions } from '../integrations/declared.js';
|
|
455
455
|
export { LOCKFILES };
|
|
456
456
|
export const manager = (into) => managerOf(into, existsSync);
|
|
457
457
|
const ADDS = { pnpm: 'add', yarn: 'add', bun: 'add', npm: 'install' };
|
|
@@ -489,7 +489,8 @@ export function installing(at) {
|
|
|
489
489
|
if (attached())
|
|
490
490
|
return here().fetch(at);
|
|
491
491
|
const tool = manager(at);
|
|
492
|
-
const
|
|
492
|
+
const [program = '', ...lead] = programFor(PACKAGER, at);
|
|
493
|
+
const ran = starts(program, [...lead, 'install'], { at });
|
|
493
494
|
const said = (ran.out + ran.err).trim();
|
|
494
495
|
if (!ran.there) {
|
|
495
496
|
throw new Error(tool + ' is what the lockfile in ' + at + ' picks, and it is not on this machine, so nothing here can fetch ' +
|
package/dist/integrations/cli.ts
CHANGED
|
@@ -8,11 +8,10 @@ import { fileURLToPath } from 'node:url'
|
|
|
8
8
|
import { CHANNEL, FOLDER, across, attached, createFileSync, existsSync, here, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from '../integrations/disk.ts'
|
|
9
9
|
import { VAULT_DIR } from '../integrations/vault.ts'
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { LOCKFILES, ORDERS, PACKAGER, REACH, managerOf, programOf, unlisted, type Answer, type How, type Order, type Ran, type Recorded, type Running } from '../integrations/target.ts'
|
|
12
12
|
import { BESIDE, CLI } from '../core/invoked.ts'
|
|
13
|
-
import { valuesIn } from '../core/rows.ts'
|
|
14
13
|
import { THING } from '../core/scope.ts'
|
|
15
|
-
import { findTree
|
|
14
|
+
import { findTree } from '../core/tree.ts'
|
|
16
15
|
|
|
17
16
|
export interface Starting {
|
|
18
17
|
|
|
@@ -180,8 +179,8 @@ export function claims(root: string, runs: string): Held {
|
|
|
180
179
|
return { by: { pid: 0, runs: '', since: Date.now() } }
|
|
181
180
|
}
|
|
182
181
|
|
|
183
|
-
export function programFor(name: string, at: string): string {
|
|
184
|
-
const found = programOf(name, at, existsSync)
|
|
182
|
+
export function programFor(name: string, at: string): readonly string[] {
|
|
183
|
+
const found = programOf(name, at, existsSync, (path) => readFileSync(path, 'utf8'))
|
|
185
184
|
if (found === undefined) throw new Error(unlisted(name))
|
|
186
185
|
return found
|
|
187
186
|
}
|
|
@@ -339,6 +338,24 @@ const READS: ReadonlySet<string> = new Set(Object.entries(ORDERS).filter(([order
|
|
|
339
338
|
|
|
340
339
|
function kept(one: Serving, asked: Order, held: Answer): void {
|
|
341
340
|
if (READS.has(asked.order) && held.answered !== 'refused') one.known.set(told(asked), held)
|
|
341
|
+
if (asked.order !== 'write' || held.answered !== ORDERS.write) return
|
|
342
|
+
one.known.set(told({ order: 'read', at: asked.at }), { answered: 'read', said: asked.said ?? '' })
|
|
343
|
+
one.known.set(told({ order: 'kind', at: asked.at }), { answered: 'kind', found: 'file' })
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const CHANGES: ReadonlySet<string> = new Set(['write', 'remove'])
|
|
347
|
+
|
|
348
|
+
const within = (at: string, under: string): boolean => under === '' || at === under || at.startsWith(under + '/')
|
|
349
|
+
|
|
350
|
+
function forgets(one: Serving, asked: Order): void {
|
|
351
|
+
if (!CHANGES.has(asked.order)) {
|
|
352
|
+
one.known.clear()
|
|
353
|
+
return
|
|
354
|
+
}
|
|
355
|
+
for (const key of [...one.known.keys()]) {
|
|
356
|
+
const [order = '', at = ''] = JSON.parse(key) as readonly string[]
|
|
357
|
+
if (order === 'real' || within(at, asked.at) || within(asked.at, at)) one.known.delete(key)
|
|
358
|
+
}
|
|
342
359
|
}
|
|
343
360
|
|
|
344
361
|
const plainly = (one: Order): string => one.order + ' ' + (one.at === '' ? '.' : one.at)
|
|
@@ -392,7 +409,7 @@ function watching(one: Serving): void {
|
|
|
392
409
|
reply(one.dir, short, known)
|
|
393
410
|
continue
|
|
394
411
|
}
|
|
395
|
-
if (!READS.has(asked.order)) one
|
|
412
|
+
if (!READS.has(asked.order)) forgets(one, asked)
|
|
396
413
|
const due = one.replaying.shift()
|
|
397
414
|
if (due !== undefined) {
|
|
398
415
|
if (told(due.order) === told(asked)) {
|
|
@@ -515,42 +532,15 @@ export function running(name: string, subcommands: Readonly<Record<string, strin
|
|
|
515
532
|
? async (args, shows, within, how) => served(word, args, within, how)
|
|
516
533
|
: async (args, shows, within, how) => {
|
|
517
534
|
const where = how?.at ?? at
|
|
518
|
-
const program = programFor(name, where)
|
|
519
|
-
if ((shows ?? false) !== false) return handed(where, program, [word, ...args], shows ?? false, within, how?.hears)
|
|
520
|
-
return await started(program, [word, ...args], { at: where, ...(within === undefined ? {} : { within }), ...(how?.hears === undefined ? {} : { hears: how.hears }) })
|
|
535
|
+
const [program = '', ...lead] = programFor(name, where)
|
|
536
|
+
if ((shows ?? false) !== false) return handed(where, program, [...lead, word, ...args], shows ?? false, within, how?.hears)
|
|
537
|
+
return await started(program, [...lead, word, ...args], { at: where, ...(within === undefined ? {} : { within }), ...(how?.hears === undefined ? {} : { hears: how.hears }) })
|
|
521
538
|
}
|
|
522
539
|
}
|
|
523
540
|
return out
|
|
524
541
|
}
|
|
525
542
|
|
|
526
|
-
|
|
527
|
-
readonly TARGETS?: readonly Target[]
|
|
528
|
-
readonly CALLS?: readonly Call[]
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
function sheet(at: string): Sheet {
|
|
532
|
-
const path = inTree(findTree(at), 'targets.ts')
|
|
533
|
-
return existsSync(path) ? (valuesIn(readFileSync(path, 'utf8')) as Sheet) : {}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
export interface Expansion {
|
|
537
|
-
readonly program: string
|
|
538
|
-
readonly target: Target
|
|
539
|
-
readonly calls: readonly Call[]
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
export function expansions(at: string): readonly Expansion[] {
|
|
543
|
-
const held = sheet(at)
|
|
544
|
-
return (held.TARGETS ?? [])
|
|
545
|
-
.filter((one) => one.id.startsWith(REACH.cli))
|
|
546
|
-
.map((one) => ({ program: one.id.slice(REACH.cli.length), target: one, calls: (held.CALLS ?? []).filter((each) => each.of === one.id) }))
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
export function calls(target: string, at: string): Running {
|
|
550
|
-
const named: Record<string, string> = {}
|
|
551
|
-
for (const one of sheet(at).CALLS ?? []) if (one.of === target) named[one.id.replace(CALL_PREFIX, '')] = one.path
|
|
552
|
-
return running(target.replace(REACH.cli, ''), named, at)
|
|
553
|
-
}
|
|
543
|
+
export { calls, expansions, type Expansion } from '../integrations/declared.ts'
|
|
554
544
|
|
|
555
545
|
export { LOCKFILES }
|
|
556
546
|
|
|
@@ -597,7 +587,8 @@ export function needing(into: string, needs: Readonly<Record<string, string>>):
|
|
|
597
587
|
export function installing(at: string): string {
|
|
598
588
|
if (attached()) return here().fetch(at)
|
|
599
589
|
const tool = manager(at)
|
|
600
|
-
const
|
|
590
|
+
const [program = '', ...lead] = programFor(PACKAGER, at)
|
|
591
|
+
const ran = starts(program, [...lead, 'install'], { at })
|
|
601
592
|
const said = (ran.out + ran.err).trim()
|
|
602
593
|
if (!ran.there) {
|
|
603
594
|
throw new Error(
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Call, type Running, type Target } from '../integrations/target.ts';
|
|
2
|
+
export interface Expansion {
|
|
3
|
+
readonly program: string;
|
|
4
|
+
readonly target: Target;
|
|
5
|
+
readonly calls: readonly Call[];
|
|
6
|
+
}
|
|
7
|
+
export declare function expansions(at: string): readonly Expansion[];
|
|
8
|
+
export declare function calls(target: string, at: string): Running;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { running } from '../integrations/cli.js';
|
|
2
|
+
import { existsSync, readFileSync } from '../integrations/disk.js';
|
|
3
|
+
import { CALL_PREFIX, REACH } from '../integrations/target.js';
|
|
4
|
+
import { valuesIn } from '../core/rows.js';
|
|
5
|
+
import { findTree, inTree } from '../core/tree.js';
|
|
6
|
+
function sheet(at) {
|
|
7
|
+
const path = inTree(findTree(at), 'targets.ts');
|
|
8
|
+
return existsSync(path) ? valuesIn(readFileSync(path, 'utf8')) : {};
|
|
9
|
+
}
|
|
10
|
+
export function expansions(at) {
|
|
11
|
+
const held = sheet(at);
|
|
12
|
+
return (held.TARGETS ?? [])
|
|
13
|
+
.filter((one) => one.id.startsWith(REACH.cli))
|
|
14
|
+
.map((one) => ({ program: one.id.slice(REACH.cli.length), target: one, calls: (held.CALLS ?? []).filter((each) => each.of === one.id) }));
|
|
15
|
+
}
|
|
16
|
+
export function calls(target, at) {
|
|
17
|
+
const named = {};
|
|
18
|
+
for (const one of sheet(at).CALLS ?? [])
|
|
19
|
+
if (one.of === target)
|
|
20
|
+
named[one.id.replace(CALL_PREFIX, '')] = one.path;
|
|
21
|
+
return running(target.replace(REACH.cli, ''), named, at);
|
|
22
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { running } from '../integrations/cli.ts'
|
|
2
|
+
import { existsSync, readFileSync } from '../integrations/disk.ts'
|
|
3
|
+
import { CALL_PREFIX, REACH, type Call, type Running, type Target } from '../integrations/target.ts'
|
|
4
|
+
import { valuesIn } from '../core/rows.ts'
|
|
5
|
+
import { findTree, inTree } from '../core/tree.ts'
|
|
6
|
+
|
|
7
|
+
interface Sheet {
|
|
8
|
+
readonly TARGETS?: readonly Target[]
|
|
9
|
+
readonly CALLS?: readonly Call[]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function sheet(at: string): Sheet {
|
|
13
|
+
const path = inTree(findTree(at), 'targets.ts')
|
|
14
|
+
return existsSync(path) ? (valuesIn(readFileSync(path, 'utf8')) as Sheet) : {}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Expansion {
|
|
18
|
+
readonly program: string
|
|
19
|
+
readonly target: Target
|
|
20
|
+
readonly calls: readonly Call[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function expansions(at: string): readonly Expansion[] {
|
|
24
|
+
const held = sheet(at)
|
|
25
|
+
return (held.TARGETS ?? [])
|
|
26
|
+
.filter((one) => one.id.startsWith(REACH.cli))
|
|
27
|
+
.map((one) => ({ program: one.id.slice(REACH.cli.length), target: one, calls: (held.CALLS ?? []).filter((each) => each.of === one.id) }))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function calls(target: string, at: string): Running {
|
|
31
|
+
const named: Record<string, string> = {}
|
|
32
|
+
for (const one of sheet(at).CALLS ?? []) if (one.of === target) named[one.id.replace(CALL_PREFIX, '')] = one.path
|
|
33
|
+
return running(target.replace(REACH.cli, ''), named, at)
|
|
34
|
+
}
|
|
@@ -178,7 +178,7 @@ export declare const unreachable: (targets: readonly Target[]) => readonly strin
|
|
|
178
178
|
export declare const LOCKFILES: Readonly<Record<string, string>>;
|
|
179
179
|
export declare const PACKAGER = "packager";
|
|
180
180
|
export declare const managerOf: (at: string, there: (path: string) => boolean) => string;
|
|
181
|
-
export declare function programOf(name: string, at: string, there: (path: string) => boolean): string | undefined;
|
|
181
|
+
export declare function programOf(name: string, at: string, there: (path: string) => boolean, read: (path: string) => string): readonly string[] | undefined;
|
|
182
182
|
export declare const unlisted: (name: string) => string;
|
|
183
183
|
export declare function misnamed(target: string, name: string): string | undefined;
|
|
184
184
|
export declare function misaccepted(targets: readonly Target[], entities: readonly string[], calls: readonly Call[]): readonly string[];
|
|
@@ -143,17 +143,31 @@ export const PACKAGER = 'packager';
|
|
|
143
143
|
const NAMED = ['git', 'thread'];
|
|
144
144
|
const RUNTIME = 'node';
|
|
145
145
|
export const managerOf = (at, there) => Object.entries(LOCKFILES).find(([lock]) => there(join(at, lock)))?.[1] ?? 'npm';
|
|
146
|
-
export function programOf(name, at, there) {
|
|
146
|
+
export function programOf(name, at, there, read) {
|
|
147
147
|
if (NAMED.includes(name))
|
|
148
|
-
return name;
|
|
148
|
+
return [name];
|
|
149
149
|
if (name === RUNTIME)
|
|
150
|
-
return execPath;
|
|
150
|
+
return [execPath];
|
|
151
151
|
if (name === PACKAGER)
|
|
152
|
-
return managerOf(at, there);
|
|
152
|
+
return [managerOf(at, there)];
|
|
153
153
|
const installed = join(at, 'node_modules', '.bin', name);
|
|
154
|
-
|
|
154
|
+
if (there(installed))
|
|
155
|
+
return [installed];
|
|
156
|
+
const shipped = join(at, 'node_modules', name);
|
|
157
|
+
const manifest = join(shipped, 'package.json');
|
|
158
|
+
if (!there(manifest))
|
|
159
|
+
return undefined;
|
|
160
|
+
let bin;
|
|
161
|
+
try {
|
|
162
|
+
bin = JSON.parse(read(manifest)).bin;
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
const entry = typeof bin === 'string' ? bin : typeof bin === 'object' && bin !== null ? bin[name] : undefined;
|
|
168
|
+
return typeof entry === 'string' ? [execPath, join(shipped, entry)] : undefined;
|
|
155
169
|
}
|
|
156
|
-
export const unlisted = (name) => '`' + REACH.cli + name + '` names ' + name + ', and nothing lists a program by that name: it is not under node_modules/.bin, so this tree did not install it; it is not git, node or thread; and it is not `' + PACKAGER + '`, the word for whichever package manager the lockfile picks. A program the tree did not install is whatever the machine happens to have, and a target on that is a shell by another name. Add the package that provides it and declare the target again, or ask for it through a declared call on `' + REACH.cli + PACKAGER + '`';
|
|
170
|
+
export const unlisted = (name) => '`' + REACH.cli + name + '` names ' + name + ', and nothing lists a program by that name: it is not linked under node_modules/.bin, and no package installed here under that name names it as its program, so this tree did not install it; it is not git, node or thread; and it is not `' + PACKAGER + '`, the word for whichever package manager the lockfile picks. A program the tree did not install is whatever the machine happens to have, and a target on that is a shell by another name. Add the package that provides it and declare the target again, or ask for it through a declared call on `' + REACH.cli + PACKAGER + '`';
|
|
157
171
|
const SHAPED = {
|
|
158
172
|
cli: /^-{0,2}[A-Za-z][A-Za-z0-9-]*$/,
|
|
159
173
|
};
|
|
@@ -412,16 +412,32 @@ const RUNTIME = 'node'
|
|
|
412
412
|
export const managerOf = (at: string, there: (path: string) => boolean): string =>
|
|
413
413
|
Object.entries(LOCKFILES).find(([lock]) => there(join(at, lock)))?.[1] ?? 'npm'
|
|
414
414
|
|
|
415
|
-
export function programOf(
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
415
|
+
export function programOf(
|
|
416
|
+
name: string,
|
|
417
|
+
at: string,
|
|
418
|
+
there: (path: string) => boolean,
|
|
419
|
+
read: (path: string) => string,
|
|
420
|
+
): readonly string[] | undefined {
|
|
421
|
+
if (NAMED.includes(name)) return [name]
|
|
422
|
+
if (name === RUNTIME) return [execPath]
|
|
423
|
+
if (name === PACKAGER) return [managerOf(at, there)]
|
|
419
424
|
const installed = join(at, 'node_modules', '.bin', name)
|
|
420
|
-
|
|
425
|
+
if (there(installed)) return [installed]
|
|
426
|
+
const shipped = join(at, 'node_modules', name)
|
|
427
|
+
const manifest = join(shipped, 'package.json')
|
|
428
|
+
if (!there(manifest)) return undefined
|
|
429
|
+
let bin: unknown
|
|
430
|
+
try {
|
|
431
|
+
bin = (JSON.parse(read(manifest)) as { readonly bin?: unknown }).bin
|
|
432
|
+
} catch {
|
|
433
|
+
return undefined
|
|
434
|
+
}
|
|
435
|
+
const entry = typeof bin === 'string' ? bin : typeof bin === 'object' && bin !== null ? (bin as Readonly<Record<string, unknown>>)[name] : undefined
|
|
436
|
+
return typeof entry === 'string' ? [execPath, join(shipped, entry)] : undefined
|
|
421
437
|
}
|
|
422
438
|
|
|
423
439
|
export const unlisted = (name: string): string =>
|
|
424
|
-
'`' + REACH.cli + name + '` names ' + name + ', and nothing lists a program by that name: it is not under node_modules/.bin, so this tree did not install it; it is not git, node or thread; and it is not `' + PACKAGER + '`, the word for whichever package manager the lockfile picks. A program the tree did not install is whatever the machine happens to have, and a target on that is a shell by another name. Add the package that provides it and declare the target again, or ask for it through a declared call on `' + REACH.cli + PACKAGER + '`'
|
|
440
|
+
'`' + REACH.cli + name + '` names ' + name + ', and nothing lists a program by that name: it is not linked under node_modules/.bin, and no package installed here under that name names it as its program, so this tree did not install it; it is not git, node or thread; and it is not `' + PACKAGER + '`, the word for whichever package manager the lockfile picks. A program the tree did not install is whatever the machine happens to have, and a target on that is a shell by another name. Add the package that provides it and declare the target again, or ask for it through a declared call on `' + REACH.cli + PACKAGER + '`'
|
|
425
441
|
|
|
426
442
|
const SHAPED: Readonly<Record<'cli', RegExp>> = {
|
|
427
443
|
cli: /^-{0,2}[A-Za-z][A-Za-z0-9-]*$/,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { starts } from '../../integrations/cli.js';
|
|
2
|
+
import { calls } from '../../integrations/declared.js';
|
|
2
3
|
import { existsSync, readFileSync } from '../../integrations/disk.js';
|
|
3
4
|
import { valuesIn } from '../../core/rows.js';
|
|
4
5
|
import { join } from 'node:path';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { starts } from '../../integrations/cli.ts'
|
|
2
|
+
import { calls } from '../../integrations/declared.ts'
|
|
2
3
|
import { existsSync, readFileSync } from '../../integrations/disk.ts'
|
|
3
4
|
import { valuesIn } from '../../core/rows.ts'
|
|
4
5
|
import { join } from 'node:path'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ROOT } from '../../core/descend.js';
|
|
2
2
|
import { valuesIn } from '../../core/rows.js';
|
|
3
|
-
import { kind } from '../../integrations/disk.js';
|
|
3
|
+
import { kind, readFileSync } from '../../integrations/disk.js';
|
|
4
4
|
import { REACH, programOf, unlisted } from '../../integrations/target.js';
|
|
5
5
|
const TARGETS = 'TARGETS';
|
|
6
6
|
const there = (path) => kind(path) === 'file';
|
|
@@ -20,7 +20,7 @@ export const slopnator = {
|
|
|
20
20
|
if (typeof one.id !== 'string' || !one.id.startsWith(REACH.cli))
|
|
21
21
|
continue;
|
|
22
22
|
const name = one.id.slice(REACH.cli.length);
|
|
23
|
-
if (programOf(name, ROOT, there) === undefined)
|
|
23
|
+
if (programOf(name, ROOT, there, (path) => readFileSync(path, 'utf8')) === undefined)
|
|
24
24
|
found.push(unlisted(name));
|
|
25
25
|
}
|
|
26
26
|
return found.length === 0 ? false : found.join('. ');
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ROOT } from '../../core/descend.ts'
|
|
2
2
|
import { valuesIn } from '../../core/rows.ts'
|
|
3
|
-
import { kind } from '../../integrations/disk.ts'
|
|
3
|
+
import { kind, readFileSync } from '../../integrations/disk.ts'
|
|
4
4
|
import { REACH, programOf, unlisted } from '../../integrations/target.ts'
|
|
5
5
|
|
|
6
6
|
import type { Slopnator } from '../slopnator.ts'
|
|
@@ -22,7 +22,7 @@ export const slopnator: Slopnator = {
|
|
|
22
22
|
for (const one of held.TARGETS ?? []) {
|
|
23
23
|
if (typeof one.id !== 'string' || !one.id.startsWith(REACH.cli)) continue
|
|
24
24
|
const name = one.id.slice(REACH.cli.length)
|
|
25
|
-
if (programOf(name, ROOT, there) === undefined) found.push(unlisted(name))
|
|
25
|
+
if (programOf(name, ROOT, there, (path) => readFileSync(path, 'utf8')) === undefined) found.push(unlisted(name))
|
|
26
26
|
}
|
|
27
27
|
return found.length === 0 ? false : found.join('. ')
|
|
28
28
|
},
|
|
@@ -1,2 +1,23 @@
|
|
|
1
|
+
import { type Call, type Target } from '../../integrations/target.ts';
|
|
2
|
+
import type { Secret } from '../../integrations/secret.ts';
|
|
3
|
+
export declare function reached(targets: readonly Target[], calls: readonly Call[], secrets: readonly Secret[]): Readonly<Record<string, {
|
|
4
|
+
readonly reach: string;
|
|
5
|
+
readonly address?: string;
|
|
6
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
7
|
+
readonly sends: readonly {
|
|
8
|
+
readonly secret: string;
|
|
9
|
+
readonly header: string;
|
|
10
|
+
readonly prefix: string;
|
|
11
|
+
}[];
|
|
12
|
+
readonly signs: readonly {
|
|
13
|
+
readonly secret: string;
|
|
14
|
+
readonly header: string;
|
|
15
|
+
readonly prefix: string;
|
|
16
|
+
}[];
|
|
17
|
+
readonly calls: Readonly<Record<string, {
|
|
18
|
+
readonly method: string | null;
|
|
19
|
+
readonly path: string;
|
|
20
|
+
}>>;
|
|
21
|
+
}>>;
|
|
1
22
|
export declare function parts(text: string): readonly string[];
|
|
2
23
|
export declare function compile(say?: boolean): Promise<number>;
|
|
@@ -27,7 +27,7 @@ async function reaching() {
|
|
|
27
27
|
const secrets = await held('secrets.ts', 'SECRETS');
|
|
28
28
|
return reached(targets, calls, secrets);
|
|
29
29
|
}
|
|
30
|
-
function reached(targets, calls, secrets) {
|
|
30
|
+
export function reached(targets, calls, secrets) {
|
|
31
31
|
const out = {};
|
|
32
32
|
for (const one of targets) {
|
|
33
33
|
const mine = calls.filter((each) => each.of === one.id && one.takes.includes(each.id));
|
|
@@ -32,7 +32,7 @@ async function reaching(): Promise<Readonly<Record<string, ReturnType<typeof rea
|
|
|
32
32
|
return reached(targets, calls, secrets)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function reached(
|
|
35
|
+
export function reached(
|
|
36
36
|
targets: readonly Target[],
|
|
37
37
|
calls: readonly Call[],
|
|
38
38
|
secrets: readonly Secret[],
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { type Grant } from '../access.ts';
|
|
2
|
+
export declare function permitting(grants: readonly Grant[]): string;
|
|
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync } from '../../integrations/disk
|
|
|
2
2
|
import { valuesIn } from '../../core/rows.js';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { argv, stderr, stdout } from 'node:process';
|
|
5
|
-
import { exit } from '../../core/invoked.js';
|
|
5
|
+
import { exit, invoked } from '../../core/invoked.js';
|
|
6
6
|
import { PUBLIC_ROLE as PUBLIC } from '../../core/actor.js';
|
|
7
7
|
import { ROOT, descend } from '../../core/descend.js';
|
|
8
8
|
import { forbids, runChecker } from '../../core/finding.js';
|
|
@@ -14,12 +14,6 @@ function stop(why) {
|
|
|
14
14
|
exit(1);
|
|
15
15
|
}
|
|
16
16
|
const CHECKING = argv.includes('--check');
|
|
17
|
-
const pass = await descend();
|
|
18
|
-
const stopped = [...pass.broken, ...pass.findings].filter(forbids)[0];
|
|
19
|
-
if (stopped !== undefined) {
|
|
20
|
-
stop('the descent is broken, so who may ask for what is only partly known, and a gate written from half of it ' +
|
|
21
|
-
`would permit callers nobody granted — ${stopped.detail} (${stopped.file ?? ''})`);
|
|
22
|
-
}
|
|
23
17
|
async function taken(file, name, what) {
|
|
24
18
|
const at = inTree(findTree(), file);
|
|
25
19
|
if (!existsSync(at))
|
|
@@ -38,28 +32,6 @@ async function taken(file, name, what) {
|
|
|
38
32
|
stop(`${at} exports no \`${name}\` list, so nothing there states ${what}`);
|
|
39
33
|
return list;
|
|
40
34
|
}
|
|
41
|
-
const grants = await taken('access.ts', 'GRANTS', 'who may ask for what');
|
|
42
|
-
const operations = [...woven(pass, types(pass))].map(([id]) => ({
|
|
43
|
-
id,
|
|
44
|
-
describes: pass.stated.get(id)?.describes ?? '',
|
|
45
|
-
}));
|
|
46
|
-
for (const found of [unanswerable(grants)]) {
|
|
47
|
-
if (found.length > 0)
|
|
48
|
-
stop(found.join('; '));
|
|
49
|
-
}
|
|
50
|
-
const twice = grantedTwice(grants);
|
|
51
|
-
if (twice.length > 0) {
|
|
52
|
-
stop(`${twice.map((one) => `\`${one}\``).join(', ')} ${twice.length === 1 ? 'is granted' : 'are granted'} more than once, ` +
|
|
53
|
-
'so two arms answer to one id and either may permit. One id, one policy — rename one of them, or delete the ' +
|
|
54
|
-
'arm that is not meant to stand');
|
|
55
|
-
}
|
|
56
|
-
const open = opensToEverybody(grants);
|
|
57
|
-
if (open.length > 0) {
|
|
58
|
-
stop(`${open.map((one) => `\`${one.id}\``).join(', ')} names no roles or entitlements and states no condition that ` +
|
|
59
|
-
'reads the caller, so who may run this is left unsaid rather than decided. If it is meant to be open, say so: ' +
|
|
60
|
-
`\`to: { roles: ['${PUBLIC}'] }\` is the role an unauthenticated caller already wears, and naming it puts ` +
|
|
61
|
-
'that decision in the sheet. Otherwise name the roles that may, or state a `when` saying whose row it is');
|
|
62
|
-
}
|
|
63
35
|
const said = (held) => JSON.stringify(held);
|
|
64
36
|
const used = new Set();
|
|
65
37
|
function reads(one, grant) {
|
|
@@ -133,7 +105,8 @@ const COMPARES = [
|
|
|
133
105
|
' return left >= other',
|
|
134
106
|
'}',
|
|
135
107
|
];
|
|
136
|
-
function permitting() {
|
|
108
|
+
export function permitting(grants) {
|
|
109
|
+
used.clear();
|
|
137
110
|
const arms = grants.flatMap((one) => {
|
|
138
111
|
const parts = [...wears(one), ...(one.when === undefined ? [] : [predicate(one.when, one)])];
|
|
139
112
|
return [
|
|
@@ -168,22 +141,54 @@ function permitting() {
|
|
|
168
141
|
].join('\n');
|
|
169
142
|
}
|
|
170
143
|
const RUNS = 'thread permits';
|
|
171
|
-
|
|
172
|
-
const
|
|
173
|
-
const
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
144
|
+
async function run() {
|
|
145
|
+
const pass = await descend();
|
|
146
|
+
const stopped = [...pass.broken, ...pass.findings].filter(forbids)[0];
|
|
147
|
+
if (stopped !== undefined) {
|
|
148
|
+
stop('the descent is broken, so who may ask for what is only partly known, and a gate written from half of it ' +
|
|
149
|
+
`would permit callers nobody granted — ${stopped.detail} (${stopped.file ?? ''})`);
|
|
150
|
+
}
|
|
151
|
+
const grants = await taken('access.ts', 'GRANTS', 'who may ask for what');
|
|
152
|
+
const operations = [...woven(pass, types(pass))].map(([id]) => ({
|
|
153
|
+
id,
|
|
154
|
+
describes: pass.stated.get(id)?.describes ?? '',
|
|
155
|
+
}));
|
|
156
|
+
for (const found of [unanswerable(grants)]) {
|
|
157
|
+
if (found.length > 0)
|
|
158
|
+
stop(found.join('; '));
|
|
159
|
+
}
|
|
160
|
+
const twice = grantedTwice(grants);
|
|
161
|
+
if (twice.length > 0) {
|
|
162
|
+
stop(`${twice.map((one) => `\`${one}\``).join(', ')} ${twice.length === 1 ? 'is granted' : 'are granted'} more than once, ` +
|
|
163
|
+
'so two arms answer to one id and either may permit. One id, one policy — rename one of them, or delete the ' +
|
|
164
|
+
'arm that is not meant to stand');
|
|
165
|
+
}
|
|
166
|
+
const open = opensToEverybody(grants);
|
|
167
|
+
if (open.length > 0) {
|
|
168
|
+
stop(`${open.map((one) => `\`${one.id}\``).join(', ')} names no roles or entitlements and states no condition that ` +
|
|
169
|
+
'reads the caller, so who may run this is left unsaid rather than decided. If it is meant to be open, say so: ' +
|
|
170
|
+
`\`to: { roles: ['${PUBLIC}'] }\` is the role an unauthenticated caller already wears, and naming it puts ` +
|
|
171
|
+
'that decision in the sheet. Otherwise name the roles that may, or state a `when` saying whose row it is');
|
|
172
|
+
}
|
|
173
|
+
const permitted = resolve(ROOT, PERMITS_AT);
|
|
174
|
+
const content = permitting(grants);
|
|
175
|
+
const count = `${String(grants.length)} grant(s) over ${String(operations.length)} operation(s)`;
|
|
176
|
+
if (CHECKING) {
|
|
177
|
+
const findings = [];
|
|
178
|
+
const current = existsSync(permitted) ? readFileSync(permitted, 'utf8') : '';
|
|
179
|
+
if (current !== content) {
|
|
180
|
+
findings.push({
|
|
181
|
+
file: PERMITS_AT,
|
|
182
|
+
detail: 'is not what this app grants',
|
|
183
|
+
instead: `run \`${RUNS}\` and commit what it writes. Never edit this file — a branch here exists because a grant was declared, and an edit widens or narrows access nobody agreed to`,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
runChecker('permits', findings, count);
|
|
187
|
+
exit(findings.length === 0 ? 0 : 1);
|
|
183
188
|
}
|
|
184
|
-
|
|
185
|
-
|
|
189
|
+
writeFileSync(permitted, content);
|
|
190
|
+
stdout.write(`permits: wrote ${PERMITS_AT} — ${count}. Dispatch imports this check itself, so every operation passes it; ` +
|
|
191
|
+
'`thread grant` adds a grant, and a refusal no grant can say is an invariant on the entity, or a rule from `thread create rule`.\n');
|
|
186
192
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
'`thread grant` adds a grant, and a refusal no grant can say is an invariant on the entity, or a rule from `thread create rule`.\n');
|
|
193
|
+
if (invoked(import.meta.url))
|
|
194
|
+
await run();
|
|
@@ -3,7 +3,7 @@ import { valuesIn } from '../../core/rows.ts'
|
|
|
3
3
|
import { resolve } from 'node:path'
|
|
4
4
|
import { argv, stderr, stdout } from 'node:process'
|
|
5
5
|
|
|
6
|
-
import { exit } from '../../core/invoked.ts'
|
|
6
|
+
import { exit, invoked } from '../../core/invoked.ts'
|
|
7
7
|
import { PUBLIC_ROLE as PUBLIC } from '../../core/actor.ts'
|
|
8
8
|
import { ROOT, descend } from '../../core/descend.ts'
|
|
9
9
|
import { forbids, runChecker, type Finding } from '../../core/finding.ts'
|
|
@@ -20,16 +20,6 @@ function stop(why: string): never {
|
|
|
20
20
|
|
|
21
21
|
const CHECKING = argv.includes('--check')
|
|
22
22
|
|
|
23
|
-
const pass = await descend()
|
|
24
|
-
|
|
25
|
-
const stopped = [...pass.broken, ...pass.findings].filter(forbids)[0]
|
|
26
|
-
if (stopped !== undefined) {
|
|
27
|
-
stop(
|
|
28
|
-
'the descent is broken, so who may ask for what is only partly known, and a gate written from half of it ' +
|
|
29
|
-
`would permit callers nobody granted — ${stopped.detail} (${stopped.file ?? ''})`,
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
23
|
async function taken<T>(file: string, name: string, what: string): Promise<readonly T[]> {
|
|
34
24
|
const at = inTree(findTree(), file)
|
|
35
25
|
if (!existsSync(at)) stop(`${at} is where this app states ${what}, and it is not there`)
|
|
@@ -48,36 +38,6 @@ async function taken<T>(file: string, name: string, what: string): Promise<reado
|
|
|
48
38
|
return list as readonly T[]
|
|
49
39
|
}
|
|
50
40
|
|
|
51
|
-
const grants = await taken<Grant>('access.ts', 'GRANTS', 'who may ask for what')
|
|
52
|
-
|
|
53
|
-
const operations = [...woven(pass, types(pass))].map(([id]) => ({
|
|
54
|
-
id,
|
|
55
|
-
describes: pass.stated.get(id)?.describes ?? '',
|
|
56
|
-
}))
|
|
57
|
-
|
|
58
|
-
for (const found of [unanswerable(grants)]) {
|
|
59
|
-
if (found.length > 0) stop(found.join('; '))
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const twice = grantedTwice(grants)
|
|
63
|
-
if (twice.length > 0) {
|
|
64
|
-
stop(
|
|
65
|
-
`${twice.map((one) => `\`${one}\``).join(', ')} ${twice.length === 1 ? 'is granted' : 'are granted'} more than once, ` +
|
|
66
|
-
'so two arms answer to one id and either may permit. One id, one policy — rename one of them, or delete the ' +
|
|
67
|
-
'arm that is not meant to stand',
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const open = opensToEverybody(grants)
|
|
72
|
-
if (open.length > 0) {
|
|
73
|
-
stop(
|
|
74
|
-
`${open.map((one) => `\`${one.id}\``).join(', ')} names no roles or entitlements and states no condition that ` +
|
|
75
|
-
'reads the caller, so who may run this is left unsaid rather than decided. If it is meant to be open, say so: ' +
|
|
76
|
-
`\`to: { roles: ['${PUBLIC}'] }\` is the role an unauthenticated caller already wears, and naming it puts ` +
|
|
77
|
-
'that decision in the sheet. Otherwise name the roles that may, or state a `when` saying whose row it is',
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
41
|
const said = (held: unknown): string => JSON.stringify(held)
|
|
82
42
|
|
|
83
43
|
const used = new Set<readonly string[]>()
|
|
@@ -156,7 +116,8 @@ const COMPARES = [
|
|
|
156
116
|
'}',
|
|
157
117
|
]
|
|
158
118
|
|
|
159
|
-
function permitting(): string {
|
|
119
|
+
export function permitting(grants: readonly Grant[]): string {
|
|
120
|
+
used.clear()
|
|
160
121
|
const arms = grants.flatMap((one) => {
|
|
161
122
|
const parts = [...wears(one), ...(one.when === undefined ? [] : [predicate(one.when, one)])]
|
|
162
123
|
return [
|
|
@@ -197,28 +158,72 @@ function permitting(): string {
|
|
|
197
158
|
|
|
198
159
|
const RUNS = 'thread permits'
|
|
199
160
|
|
|
200
|
-
|
|
161
|
+
async function run(): Promise<void> {
|
|
162
|
+
const pass = await descend()
|
|
163
|
+
|
|
164
|
+
const stopped = [...pass.broken, ...pass.findings].filter(forbids)[0]
|
|
165
|
+
if (stopped !== undefined) {
|
|
166
|
+
stop(
|
|
167
|
+
'the descent is broken, so who may ask for what is only partly known, and a gate written from half of it ' +
|
|
168
|
+
`would permit callers nobody granted — ${stopped.detail} (${stopped.file ?? ''})`,
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const grants = await taken<Grant>('access.ts', 'GRANTS', 'who may ask for what')
|
|
201
173
|
|
|
202
|
-
const
|
|
174
|
+
const operations = [...woven(pass, types(pass))].map(([id]) => ({
|
|
175
|
+
id,
|
|
176
|
+
describes: pass.stated.get(id)?.describes ?? '',
|
|
177
|
+
}))
|
|
203
178
|
|
|
204
|
-
const
|
|
179
|
+
for (const found of [unanswerable(grants)]) {
|
|
180
|
+
if (found.length > 0) stop(found.join('; '))
|
|
181
|
+
}
|
|
205
182
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
183
|
+
const twice = grantedTwice(grants)
|
|
184
|
+
if (twice.length > 0) {
|
|
185
|
+
stop(
|
|
186
|
+
`${twice.map((one) => `\`${one}\``).join(', ')} ${twice.length === 1 ? 'is granted' : 'are granted'} more than once, ` +
|
|
187
|
+
'so two arms answer to one id and either may permit. One id, one policy — rename one of them, or delete the ' +
|
|
188
|
+
'arm that is not meant to stand',
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const open = opensToEverybody(grants)
|
|
193
|
+
if (open.length > 0) {
|
|
194
|
+
stop(
|
|
195
|
+
`${open.map((one) => `\`${one.id}\``).join(', ')} names no roles or entitlements and states no condition that ` +
|
|
196
|
+
'reads the caller, so who may run this is left unsaid rather than decided. If it is meant to be open, say so: ' +
|
|
197
|
+
`\`to: { roles: ['${PUBLIC}'] }\` is the role an unauthenticated caller already wears, and naming it puts ` +
|
|
198
|
+
'that decision in the sheet. Otherwise name the roles that may, or state a `when` saying whose row it is',
|
|
199
|
+
)
|
|
215
200
|
}
|
|
216
|
-
|
|
217
|
-
|
|
201
|
+
|
|
202
|
+
const permitted = resolve(ROOT, PERMITS_AT)
|
|
203
|
+
|
|
204
|
+
const content = permitting(grants)
|
|
205
|
+
|
|
206
|
+
const count = `${String(grants.length)} grant(s) over ${String(operations.length)} operation(s)`
|
|
207
|
+
|
|
208
|
+
if (CHECKING) {
|
|
209
|
+
const findings: Finding[] = []
|
|
210
|
+
const current = existsSync(permitted) ? readFileSync(permitted, 'utf8') : ''
|
|
211
|
+
if (current !== content) {
|
|
212
|
+
findings.push({
|
|
213
|
+
file: PERMITS_AT,
|
|
214
|
+
detail: 'is not what this app grants',
|
|
215
|
+
instead: `run \`${RUNS}\` and commit what it writes. Never edit this file — a branch here exists because a grant was declared, and an edit widens or narrows access nobody agreed to`,
|
|
216
|
+
})
|
|
217
|
+
}
|
|
218
|
+
runChecker('permits', findings, count)
|
|
219
|
+
exit(findings.length === 0 ? 0 : 1)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
writeFileSync(permitted, content)
|
|
223
|
+
stdout.write(
|
|
224
|
+
`permits: wrote ${PERMITS_AT} — ${count}. Dispatch imports this check itself, so every operation passes it; ` +
|
|
225
|
+
'`thread grant` adds a grant, and a refusal no grant can say is an invariant on the entity, or a rule from `thread create rule`.\n',
|
|
226
|
+
)
|
|
218
227
|
}
|
|
219
228
|
|
|
220
|
-
|
|
221
|
-
stdout.write(
|
|
222
|
-
`permits: wrote ${PERMITS_AT} — ${count}. Dispatch imports this check itself, so every operation passes it; ` +
|
|
223
|
-
'`thread grant` adds a grant, and a refusal no grant can say is an invariant on the entity, or a rule from `thread create rule`.\n',
|
|
224
|
-
)
|
|
229
|
+
if (invoked(import.meta.url)) await run()
|