@palettelab/cli 0.3.33 → 0.3.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -509,6 +509,51 @@ management. For advanced Qdrant features, use `ctx.vector.client()` with
509
509
  `collection_name()`, `scoped_filter()`, `merge_filter()`, `scoped_payload()`,
510
510
  and `scoped_point()` so custom calls remain scoped.
511
511
 
512
+ Common managed-service commands:
513
+
514
+ ```python
515
+ # Redis strings, counters, and key discovery
516
+ await ctx.redis.get("key", default=None)
517
+ await ctx.redis.set("key", {"json": True}, ttl=600)
518
+ await ctx.redis.delete("key1", "key2")
519
+ await ctx.redis.exists("key")
520
+ await ctx.redis.expire("key", 300)
521
+ await ctx.redis.ttl("key")
522
+ await ctx.redis.incr("counter")
523
+ await ctx.redis.decr("counter")
524
+ await ctx.redis.scan(prefix="cache:", limit=100)
525
+
526
+ # Redis hashes, lists, sets, sorted sets, streams, locks
527
+ await ctx.redis.hset("hash", "field", {"value": 1})
528
+ await ctx.redis.hgetall("hash")
529
+ await ctx.redis.lpush("queue", {"job": 1})
530
+ await ctx.redis.lrange("queue", 0, -1)
531
+ await ctx.redis.sadd("tags", "red", "blue")
532
+ await ctx.redis.smembers("tags")
533
+ await ctx.redis.zadd("scores", {"alice": 10})
534
+ await ctx.redis.zrange("scores", 0, -1, with_scores=True)
535
+ await ctx.redis.xadd("events", {"type": "created"})
536
+ await ctx.redis.xread({"events": "0-0"}, count=10)
537
+ await ctx.redis.lock("invoice:1", token, ttl=30)
538
+ await ctx.redis.unlock("invoice:1", token)
539
+
540
+ # Redis provider-style data-plane calls
541
+ await ctx.redis.execute("MSET", "a", "1", "b", "2")
542
+ values = await ctx.redis.execute("MGET", "a", "b")
543
+
544
+ # Vector search
545
+ await ctx.vector.upsert_texts("knowledge", [{"id": "doc-1", "text": "Text"}])
546
+ await ctx.vector.upsert_vectors("knowledge", [{"id": "vec-1", "vector": [0.1, 0.2]}])
547
+ hits = await ctx.vector.search("knowledge", query="invoice policy", top_k=10)
548
+ record = await ctx.vector.get("knowledge", "doc-1")
549
+ await ctx.vector.delete("knowledge", ["doc-1"])
550
+ await ctx.vector.delete_index("knowledge")
551
+ stats = await ctx.vector.stats("knowledge")
552
+ ```
553
+
554
+ Blocked Redis control-plane commands include `FLUSHDB`, `FLUSHALL`, `CONFIG`,
555
+ `KEYS`, `CLUSTER`, `SCRIPT`, `EVAL`, `FUNCTION`, and `SELECT`.
556
+
512
557
  ### `pltt login`
513
558
 
514
559
  Save a Palette sandbox or production environment URL plus token in `~/.palette/config.json` with file mode `0600`. Environment variables still override the stored token when present.
@@ -344,6 +344,52 @@ Alembic migrations. Route code intentionally has data permissions only; it
344
344
  cannot access Palette core tables, another app's schema, or another org's
345
345
  RLS-protected rows.
346
346
 
347
+ Common `ctx.db` operations:
348
+
349
+ ```python
350
+ from sqlalchemy import delete, func, insert, select, text, update
351
+
352
+ rows = (await ctx.db.execute(select(Invoice))).scalars().all()
353
+ invoice = await ctx.db.scalar(select(Invoice).where(Invoice.id == invoice_id))
354
+ count = await ctx.db.scalar(select(func.count()).select_from(Invoice))
355
+
356
+ ctx.db.add(Invoice(customer_name="A", amount=10, status="draft"))
357
+ ctx.db.add_all([
358
+ Invoice(customer_name="B", amount=20, status="draft"),
359
+ Invoice(customer_name="C", amount=30, status="draft"),
360
+ ])
361
+ await ctx.db.execute(insert(Invoice).values(customer_name="D", amount=40, status="draft"))
362
+ await ctx.db.execute(update(Invoice).where(Invoice.id == invoice_id).values(status="paid"))
363
+ await ctx.db.execute(delete(Invoice).where(Invoice.id == invoice_id))
364
+
365
+ async with ctx.db.begin():
366
+ ctx.db.add(Invoice(customer_name="E", amount=50, status="queued"))
367
+
368
+ await ctx.db.commit()
369
+ await ctx.db.rollback()
370
+ await ctx.db.refresh(invoice)
371
+
372
+ result = await ctx.db.execute(
373
+ text("select id, customer_name from finance_tools__invoices where amount > :amount"),
374
+ {"amount": 100},
375
+ )
376
+ rows = result.mappings().all()
377
+ ```
378
+
379
+ Common migration operations:
380
+
381
+ ```python
382
+ op.create_table(...)
383
+ op.add_column(...)
384
+ op.alter_column(...)
385
+ op.create_index(...)
386
+ op.create_unique_constraint(...)
387
+ op.create_foreign_key(...)
388
+ op.drop_index(...)
389
+ op.drop_column(...)
390
+ ensure_org_rls(op, "finance_tools__invoices")
391
+ ```
392
+
347
393
  ## 8. Data Rooms From Python
348
394
 
349
395
  Use `ctx.data_rooms` when backend code needs to create folders, find files, or
@@ -569,6 +615,93 @@ while blocking server/admin commands. `ctx.vector.client()` returns the Qdrant
569
615
  client for custom calls; combine it with `collection_name()`, `scoped_filter()`,
570
616
  `merge_filter()`, `scoped_payload()`, and `scoped_point()` to preserve isolation.
571
617
 
618
+ Common `ctx.redis` commands:
619
+
620
+ ```python
621
+ await ctx.redis.get("key", default=None)
622
+ await ctx.redis.set("key", {"json": True}, ttl=600, nx=False, xx=False)
623
+ await ctx.redis.delete("key1", "key2")
624
+ await ctx.redis.exists("key")
625
+ await ctx.redis.expire("key", 300)
626
+ await ctx.redis.ttl("key")
627
+ await ctx.redis.incr("counter", 1)
628
+ await ctx.redis.decr("counter", 1)
629
+ await ctx.redis.scan(prefix="cache:", limit=100)
630
+
631
+ await ctx.redis.hset("hash", "field", {"value": 1})
632
+ await ctx.redis.hget("hash", "field")
633
+ await ctx.redis.hgetall("hash")
634
+ await ctx.redis.hdel("hash", "field")
635
+
636
+ await ctx.redis.lpush("queue", {"job": 1})
637
+ await ctx.redis.rpush("queue", {"job": 2})
638
+ await ctx.redis.lpop("queue")
639
+ await ctx.redis.rpop("queue")
640
+ await ctx.redis.lrange("queue", 0, -1)
641
+
642
+ await ctx.redis.sadd("tags", "red", "blue")
643
+ await ctx.redis.smembers("tags")
644
+ await ctx.redis.srem("tags", "red")
645
+
646
+ await ctx.redis.zadd("scores", {"alice": 10, "bob": 8})
647
+ await ctx.redis.zrange("scores", 0, -1, with_scores=True)
648
+ await ctx.redis.zrem("scores", "bob")
649
+
650
+ await ctx.redis.enqueue("jobs", {"task": "sync"})
651
+ await ctx.redis.dequeue("jobs")
652
+ await ctx.redis.xadd("events", {"type": "created"})
653
+ await ctx.redis.xread({"events": "0-0"}, count=10)
654
+ await ctx.redis.lock("invoice:1", token, ttl=30)
655
+ await ctx.redis.unlock("invoice:1", token)
656
+ ```
657
+
658
+ Provider-style Redis commands:
659
+
660
+ ```python
661
+ await ctx.redis.execute("MSET", "a", "1", "b", "2")
662
+ values = await ctx.redis.execute("MGET", "a", "b")
663
+ await ctx.redis.execute("ZUNIONSTORE", "dest", 2, "scores:1", "scores:2")
664
+ ```
665
+
666
+ Server/admin Redis commands are blocked because they would affect the shared
667
+ central Redis instance: `FLUSHDB`, `FLUSHALL`, `CONFIG`, `KEYS`, `CLUSTER`,
668
+ `SCRIPT`, `EVAL`, `FUNCTION`, `SELECT`, and similar control-plane commands.
669
+
670
+ Common `ctx.vector` commands:
671
+
672
+ ```python
673
+ await ctx.vector.upsert_texts(
674
+ "knowledge",
675
+ [{"id": "doc-1", "text": "Text to embed", "metadata": {"type": "note"}}],
676
+ )
677
+ await ctx.vector.upsert_vectors(
678
+ "knowledge",
679
+ [{"id": "vec-1", "vector": [0.1, 0.2], "metadata": {"type": "manual"}}],
680
+ )
681
+ hits = await ctx.vector.search("knowledge", query="invoice policy", top_k=10)
682
+ hits = await ctx.vector.search("knowledge", vector=[0.1, 0.2], filter={"type": "note"})
683
+ record = await ctx.vector.get("knowledge", "doc-1")
684
+ await ctx.vector.delete("knowledge", ["doc-1"])
685
+ await ctx.vector.delete_index("knowledge")
686
+ stats = await ctx.vector.stats("knowledge")
687
+ ```
688
+
689
+ Advanced Qdrant calls should use scoped helpers:
690
+
691
+ ```python
692
+ client = await ctx.vector.client()
693
+ collection = ctx.vector.collection_name()
694
+ query_filter = ctx.vector.scoped_filter("knowledge", {"type": "note"})
695
+ point = ctx.vector.scoped_point(
696
+ "knowledge",
697
+ id="doc-2",
698
+ vector=[0.1, 0.2],
699
+ text="Indexed text",
700
+ metadata={"type": "note"},
701
+ )
702
+ await client.upsert(collection_name=collection, points=[point])
703
+ ```
704
+
572
705
  ## 10. Lifecycle Hooks
573
706
 
574
707
  Lifecycle hooks let an app seed defaults or clean up app-owned data when the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@palettelab/cli",
3
- "version": "0.3.33",
3
+ "version": "0.3.34",
4
4
  "description": "Developer CLI for building Palette platform plugins — no platform source access required.",
5
5
  "bin": {
6
6
  "pltt": "bin/pltt.js"